1. 程式人生 > 實用技巧 >leetcode常規演算法題覆盤(基礎篇)——線性表java實現

leetcode常規演算法題覆盤(基礎篇)——線性表java實現

根據清華大學出版社的《資料結構及應用演算法教程》第二章內容,線性表包括順序儲存模式及鏈式儲存模式,以下為根據書中內容通過java語言實現的順序表及連結串列。

其中元素型別通過泛型化進行約束。

此處特別鳴謝CSDN爪 哇大佬的部落格,地址:https://blog.csdn.net/qq_40794973/article/details/101555091?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-3&spm=1001.2101.3001.4242

順序表:

  1 import java.util.Arrays;
2 /** 3 * 順序線性表的實現 4 */ 5 public class LineList<E>{ 6   private int size; //長度 7   private Object[] array; //底層陣列 8   private final int default_length=16; //預設長度 9 /** 10 * 無參構造方法 11 */ 12   public LineList(){ 13     size = 0; 14 //使用預設長度構造陣列 15     array = new Object[default_length];
16   } 17 /** 18 * 指定長度進行構造 19 * @param length 指定初始長度 20 */ 21 public LineList(int length){ 22 if(length<0){ 23 throw new IllegalArgumentException("初始長度不合法:"+length); 24 } 25 //使用指定長度構造陣列 26 array = new Object[length]; 27 } 28 29 /** 30 * 指定初始化元素和長度進行構造 31 * @param
element 初始化元素 32 * @param length 初始化長度 33 */ 34 public LineList(E element,int length){ 35 if(length<1){ 36 throw new IllegalArgumentException("初始長度不合法:"+length); 37 } 38 //使用指定長度構造陣列 39 array = new Object[length]; 40 //初始化第一個元素 41 array[0] = element; 42 size++; 43 } 44 /** 45 * 指定初始化元素進行構造 46 * @param element 初始化元素 47 */ 48 public LineList(E element){ 49 //使用預設長度初始化陣列 50 array = new Object[default_length]; 51 //初始化第一個元素 52 array[0] = element; 53 } 54 55 /** 56 * 獲取元素個數 57 */ 58 public int size() { 59 return size; 60 } 61 62 /** 63 * 判斷是否為空 64 */ 65 public boolean isEmpty() { 66 return size==0; 67 } 68 69 /** 70 * 判斷是否包含此元素 71 */ 72 public boolean contains(E e) { 73 if(indexOf(e) == -1){ 74 return false; 75 } 76 return true; 77 } 78 79 /** 80 * 格式化為陣列 81 */ 82 public Object[] toArray() { 83 return Arrays.copyOf(array, size); 84 } 85 86 /** 87 * 向線性表尾部新增一個元素 88 * @param e 89 * @return 90 */ 91 public void add(E e) { 92 extendCapacity(size+1); 93 array[size]=e; 94 size++; 95 } 96 97 /** 98 * 擴容 99 * @param length 需要的長度 100 */ 101 private void extendCapacity(int length){ 102 //當前陣列長度和需要的長度取最大 103 int minCapacity = Math.max(array.length, length); 104 //判斷是否需要擴容 105 if(minCapacity - array.length>0){ 106 //陣列長度增加一半 107 int newLength = array.length + array.length/2; 108 //如果新的長度還比需求要小,將需求的長度作為陣列長度 109 if(newLength < minCapacity){ 110 newLength=minCapacity; 111 } 112 //陣列長度不能超過Integer.Max_Value 113 if(newLength > Integer.MAX_VALUE - 8){ 114 newLength = Integer.MAX_VALUE; 115 } 116 //陣列擴容 117 array = Arrays.copyOf(array, newLength); 118 } 119 } 120 /** 121 * 從線性表中移除所有此元素 122 * @param e 需要移除的元素 123 * @return 124 */ 125 public void removeAll(E e) { 126 if(e==null){ 127 for(int i=0;i<size;i++){ 128 if(array[i]==null){ 129 fastRemove(i); 130 } 131 } 132 }else{ 133 for(int i=0;i<size;i++){ 134 if(e.equals(array[i])){ 135 fastRemove(i); 136 } 137 } 138 } 139 } 140 141 /** 142 * 刪除索引處元素,後面的元素依次前移 143 * @param index 需要刪除的索引 144 */ 145 private void fastRemove(int index){ 146 if(size-index-1>0){ 147 //陣列從index+1開始全部前移 148 System.arraycopy(array, index+1, array, index, size-1); 149 } 150 //最後一個元素請空 151 array[--size]=null; 152 } 153 154 /** 155 * 清空線性表 156 */ 157 public void clear() { 158 //將陣列全部填充為null 159 Arrays.fill(array, null); 160 //將元素個數改為0 161 size=0; 162 } 163 /** 164 * 獲得索引處的元素 165 * @param index 166 * @return 索引處的元素 167 */ 168 @SuppressWarnings("unchecked") 169 public E get(int index) { 170 checkIndex(index); 171 return (E)array[index]; 172 } 173 174 /** 175 * 驗證是否為索引越界 176 * @param index 177 */ 178 private void checkIndex(int index){ 179 if(index>=size || index<0){ 180 throw new IndexOutOfBoundsException("索引越界"); 181 } 182 } 183 184 /** 185 * 將索引處的元素修改為新的元素 186 * @param index 索引位置 187 * @param element 元素 188 * @return 原索引處的元素 189 */ 190 @SuppressWarnings("unchecked") 191 public E set(int index, E element) { 192 checkIndex(index); 193 E e = (E)array[index]; 194 array[index]=element; 195 return e; 196 } 197 198 /** 199 * 在指定的索引處插入指定的元素 200 * @param index 索引位置 201 * @param element 元素 202 */ 203 public void add(int index, E element) { 204 //驗證索引 205 checkIndex(index); 206 //是否需要擴容 207 extendCapacity(size+1); 208 //複製陣列 209 System.arraycopy(array, index, array, index+1, size-index); 210 array[index]=element; 211 } 212 213 /** 214 * 移除索引處的元素 215 * @param index 索引 216 * @return 刪除了的元素 217 */ 218 @SuppressWarnings("unchecked") 219 public E remove(int index) { 220 checkIndex(index); 221 //取得索引位置的元素 222 E e = (E)array[index]; 223 fastRemove(index); 224 return e; 225 } 226 227 /** 228 * 取得元素第一次出現的位置的索引 229 * @param e 要查詢的元素 230 * @return 如果為-1說明線性表沒有這個元素 231 */ 232 public int indexOf(E e) { 233 if(e==null){//注意此處e==null的含義是傳入了一個值為空的e值,但e並不是沒有,還是應該在Object array裡尋找同樣為空的位置。 234 for(int i=0;i<size;i++){ 235 if(e==array[i]){ 236 return i; 237 } 238 } 239 } 240 for(int i=0;i<size;i++){ 241 if(e.equals(array[i])){ 242 return i; 243 } 244 } 245 return -1; 246 } 247 248 /** 249 * 取得元素最後一次出現的位置的索引 250 * @param e 要查詢的元素 251 * @return 如果為-1說明線性表沒有這個元素 252 */ 253 public int lastIndexOf(E e) { 254 //判斷元素是否為null 255 if(e==null){ 256 for(int i=size-1;i>=0;i--){ 257 if(e==array[i]){ 258 return i; 259 } 260 } 261 } 262 for(int i=size-1;i>=0;i--){ 263 //如果為null這裡會跑出NullPoint異常 264 //所以前面要加上驗證是否為Null 265 if(e.equals(array[i])){ 266 return i; 267 } 268 } 269 return -1; 270 } 271 272 /** 273 * 擷取線性表 274 * @param fromIndex 開始索引 275 * @param toIndex 結束索引 276 * @return 擷取的線性表 277 */ 278 @SuppressWarnings("unchecked") 279 public LineList<E> subList(int fromIndex, int toIndex) { 280 //判斷開始索引是否越界 281 if(fromIndex<0 || fromIndex >=size){ 282 throw new IndexOutOfBoundsException("開始索引越界:"+fromIndex); 283 } 284 //判斷結束索引是否越界 285 if(toIndex >=size || fromIndex <0){ 286 throw new IndexOutOfBoundsException("結束索引越界:"+toIndex); 287 } 288 //判斷開始索引和結束索引是否正確 289 if(fromIndex > toIndex){ 290 throw new IllegalArgumentException("引數不正確,開始索引應大於等於結束索引"); 291 } 292 LineList<E> list = new LineList<E>(); 293 for(int i=fromIndex,j=toIndex;i<=j;i++){ 294 list.add((E)array[i]); 295 } 296 return list; 297 } 298 }

連結串列:

①用常規方式實現有虛擬頭結點的連結串列

  1 public class LinkedList<E> {
  2     private class Node {
  3         public E e;
  4         public Node next;
  5         public Node(E e, Node next) {
  6             this.e = e;
  7             this.next = next;
  8         }
  9         public Node(E e) {
 10             this(e, null);
 11         }
 12         public Node() {
 13             this(null, null);
 14         }
 15         @Override
 16         public String toString() {
 17             return e.toString();
 18         }
 19     }
 20     private Node dummyHead;
 21     private int size;
 22     public LinkedList() {
 23         dummyHead = new Node();
 24         size = 0;
 25     }
 26     // 獲取連結串列中的元素個數
 27     public int getSize() {
 28         return size;
 29     }
 30     // 返回連結串列是否為空
 31     public boolean isEmpty() {
 32         return size == 0;
 33     }
 34     // 在連結串列的index(0-based)位置新增新的元素e
 35 // 在連結串列中不是一個常用的操作,練習用
 36     public void add(int index, E e) {
 37         if (index < 0 || index > size) {
 38             throw new IllegalArgumentException("Add failed. Illegal index.");
 39         }
 40         Node prev = dummyHead;
 41         for (int i = 0; i < index; i++) {
 42             prev = prev.next;
 43         }
 44         prev.next = new Node(e, prev.next);
 45         size++;
 46     }
 47     // 在連結串列頭新增新的元素e
 48     public void addFirst(E e) {
 49         add(0, e);
 50     }
 51     // 在連結串列末尾新增新的元素e
 52     public void addLast(E e) {
 53         add(size, e);
 54     }
 55     // 獲得連結串列的第index(0-based)個位置的元素
 56 // 在連結串列中不是一個常用的操作,練習用:
 57     public E get(int index) {
 58         if (index < 0 || index >= size) {
 59             throw new IllegalArgumentException("Get failed. Illegal index.");
 60         }
 61         Node cur = dummyHead.next;
 62         for (int i = 0; i < index; i++) {
 63             cur = cur.next;
 64         }
 65         return cur.e;
 66     }
 67     // 獲得連結串列的第一個元素
 68     public E getFirst() {
 69         return get(0);
 70     }
 71     // 獲得連結串列的最後一個元素
 72     public E getLast() {
 73         return get(size - 1);
 74     }
 75     // 修改連結串列的第index(0-based)個位置的元素為e
 76     // 在連結串列中不是一個常用的操作,練習用:
 77     public void set(int index, E e) {
 78         if (index < 0 || index >= size) {
 79             throw new IllegalArgumentException("Set failed. Illegal index.");
 80         }
 81         Node cur = dummyHead.next;
 82         for (int i = 0; i < index; i++) {
 83             cur = cur.next;
 84         }
 85         cur.e = e;
 86     }
 87     // 查詢連結串列中是否有元素e
 88     public boolean contains(E e) {
 89         Node cur = dummyHead.next;
 90         while (cur != null) {
 91             if (cur.e.equals(e)) {
 92                 return true;
 93             }
 94             cur = cur.next;
 95         }
 96         return false;
 97     }
 98     // 從連結串列中刪除index(0-based)位置的元素, 返回刪除的元素
 99     // 在連結串列中不是一個常用的操作,練習用
100     public E remove(int index) {
101         if (index < 0 || index >= size) {
102             throw new IllegalArgumentException("Remove failed. Index is illegal.");
103         }
104         Node prev = dummyHead;
105         for (int i = 0; i < index; i++) {
106             prev = prev.next;
107         }
108         Node retNode = prev.next;
109         prev.next = retNode.next;
110         retNode.next = null;
111         //疑問:這裡為什麼不釋放結點retNode?
112         size--;
113         return retNode.e;
114     }
115     // 從連結串列中刪除第一個元素, 返回刪除的元素
116     public E removeFirst() {
117         return remove(0);
118     }
119     // 從連結串列中刪除最後一個元素, 返回刪除的元素
120     public E removeLast() {
121         return remove(size - 1);
122     }
123     // 從連結串列中刪除元素e
124     public void removeElement(E e) {
125         Node prev = dummyHead;
126         while (prev.next != null) {
127             if (prev.next.e.equals(e)) {
128                 break;
129             }
130             prev = prev.next;
131         }
132         if (prev.next != null) {
133             Node delNode = prev.next;
134             prev.next = delNode.next;
135             delNode.next = null;
136             size--;
137         }
138     }
139     @Override
140     public String toString(){
141         StringBuilder res = new StringBuilder();
142         //Node cur = dummyHead.next;
143         //while(cur != null){
144         //    res.append(cur + "->");
145         //    cur = cur.next;
146         //}
147         for(Node cur = dummyHead.next ; cur != null ; cur = cur.next) {
148             res.append(cur + "->");
149         }
150         res.append("NULL");
151         return res.toString();
152     }
  }

②用遞迴的方式實現連結串列

  1 /**
  2  * Recursion
  3  */
  4 public class LinkedListR<E> {
  5     private class Node {
  6         public E e;
  7         public Node next;
  8         public Node(E e, Node next) {
  9             this.e = e;
 10             this.next = next;
 11         }
 12         public Node(E e) {
 13             this(e, null);
 14         }
 15         public Node() {
 16             this(null, null);
 17         }
 18         @Override
 19         public String toString() {
 20             return e.toString();
 21         }
 22     }
 23  
 24     // 在連結串列的遞迴實現中,我們不使用虛擬頭結點,也能無差異的處理位置0的問題:
 25     private Node head;
 26     private int size;
 27     public LinkedListR() {
 28         head = null;
 29         size = 0;
 30     }
 31     // 獲取連結串列中的元素個數
 32     public int getSize() {
 33         return size;
 34     }
 35     // 返回連結串列是否為空
 36     public boolean isEmpty() {
 37         return size == 0;
 38     }
 39     // 在連結串列的index(0-based)位置新增新的元素e
 40     public void add(int index, E e) {
 41         if (index < 0 || index > size) {
 42             throw new IllegalArgumentException("Add failed. Illegal index.");
 43         }
 44         head = add(head, index, e);
 45         size++;
 46     }
 47     // 在以node為頭結點的連結串列的index位置插入元素e,遞迴演算法
 48     private Node add(Node node, int index, E e) {
 49         if (index == 0) {
 50             return new Node(e, node);
 51         }
 52         node.next = add(node.next, index - 1, e);
 53         return node;
 54     }
 55     // 在連結串列頭新增新的元素e
 56     public void addFirst(E e) {
 57         add(0, e);
 58     }
 59     // 在連結串列末尾新增新的元素e
 60     public void addLast(E e) {
 61         add(size, e);
 62     }
 63     // 獲得連結串列的第index(0-based)個位置的元素
 64     public E get(int index) {
 65         if (index < 0 || index >= size) {
 66             throw new IllegalArgumentException("Get failed. Illegal index.");
 67         }
 68         return get(head, index);
 69     }
 70     // 在以node為頭結點的連結串列中,找到第index個元素,遞迴演算法
 71     private E get(Node node, int index) {
 72         if (index == 0) {
 73             return node.e;
 74         }
 75         return get(node.next, index - 1);
 76     }
 77     // 獲得連結串列的第一個元素
 78     public E getFirst() {
 79         return get(0);
 80     }
 81     // 獲得連結串列的最後一個元素
 82     public E getLast() {
 83         return get(size - 1);
 84     }
 85     // 修改連結串列的第index(0-based)個位置的元素為e
 86     public void set(int index, E e) {
 87         if (index < 0 || index >= size) {
 88             throw new IllegalArgumentException("Update failed. Illegal index.");
 89         }
 90         set(head, index, e);
 91     }
 92     // 修改以node為頭結點的連結串列中,第index(0-based)個位置的元素為e,遞迴演算法
 93     private void set(Node node, int index, E e) {
 94         if (index == 0) {
 95             node.e = e;
 96             return;
 97         }
 98         set(node.next, index - 1, e);
 99     }
100     // 查詢連結串列中是否有元素e
101     public boolean contains(E e) {
102         return contains(head, e);
103     }
104     // 在以node為頭結點的連結串列中,查詢是否存在元素e,遞迴演算法
105     private boolean contains(Node node, E e) {
106         if (node == null) {
107             return false;
108         }
109         if (node.e.equals(e)) {
110             return true;
111         }
112         return contains(node.next, e);
113     }
114     // 從連結串列中刪除index(0-based)位置的元素, 返回刪除的元素
115     public E remove(int index) {
116         if (index < 0 || index >= size) {
117             throw new IllegalArgumentException("Remove failed. Index is illegal.");
118         }
119         Pair<Node, E> res = remove(head, index);
120         size--;
121         head = res.getKey();
122         return res.getValue();
123     }
124     // 從以node為頭結點的連結串列中,刪除第index位置的元素,遞迴演算法
125     // 返回值包含兩個元素,刪除後的連結串列頭結點和刪除的值:)
126     private Pair<Node, E> remove(Node node, int index) {
127         if (index == 0) {
128             return new Pair<>(node.next, node.e);
129         }
130         Pair<Node, E> res = remove(node.next, index - 1);
131         node.next = res.getKey();
132         return new Pair<>(node, res.getValue());
133     }
134     // 從連結串列中刪除第一個元素, 返回刪除的元素
135     public E removeFirst() {
136         return remove(0);
137     }
138     // 從連結串列中刪除最後一個元素, 返回刪除的元素
139     public E removeLast() {
140         return remove(size - 1);
141     }
142     // 從連結串列中刪除元素e
143     public void removeElement(E e) {
144         head = removeElement(head, e);
145     }
146     // 從以node為頭結點的連結串列中,刪除元素e,遞迴演算法
147     private Node removeElement(Node node, E e) {
148         if (node == null) {
149             return null;
150         }
151         if (node.e.equals(e)) {
152             size--;
153             return node.next;
154         }
155         node.next = removeElement(node.next, e);
156         return node;
157     }
158     @Override
159     public String toString() {
160         StringBuilder res = new StringBuilder();
161         Node cur = head;
162         while (cur != null) {
163             res.append(cur + "->");
164             cur = cur.next;
165         }
166         res.append("NULL");
167         return res.toString();
168     }
169 }