1、隊列Queue,隊列也是一種線性結構,相比數組,隊列對應的操作是數組的子集,只能從一端(隊尾)添加元素,只能從另一端(隊首)取出元素。隊列是一種先進先出的數據結構(或者稱爲先到先得),First In First Out(簡稱FIFO)。
2、封裝的數組的代碼,可以實現增加,修改,刪除,查詢,動態擴容,縮容,判斷是否爲空等等方法。
1 package com.company; 2 3 4 /** 5 * 6 */ 7 public class Array<E> { 8 9 private E[] data;//定義數組 10 private int size;//數組實際的長度 11 12 /** 13 * 構造函數,傳入數組的容量capacity構造Array 14 * 15 * @param capacity 初始化數據的容量長度 16 */ 17 public Array(int capacity) { 18 // 使用泛型,可以創建任意類型的數組類型 19 data = (E[]) new Object[capacity]; 20 // 初始化數組的實際內容的長度爲0 21 size = 0; 22 } 23 24 /** 25 * 無參數的構造函數,默認數組的容量capacity=10 26 */ 27 public Array() { 28 // 無參構造函數,指定初始化數組容量長度爲0 29 this(10); 30 } 31 32 /** 33 * 獲取數組中的元素個數 34 * 35 * @return 36 */ 37 public int getSize() { 38 // 獲取到數組中的元素個數 39 return size; 40 } 41 42 /** 43 * 獲取數組的容量 44 * 45 * @return 46 */ 47 public int getCapacity() { 48 // 獲取到數組的容量 49 return data.length; 50 } 51 52 /** 53 * 返回數組是否爲空 54 * 55 * @return 56 */ 57 public boolean isEmpty() { 58 // 判斷數組的長度是否爲空 59 return size == 0; 60 } 61 62 63 /** 64 * 向所有元素後添加一個新元素 65 * 66 * @param e 67 */ 68 public void addLast(E e) { 69 // if (size == data.length) { 70 // throw new IllegalArgumentException("AddLast failed,Array is full......"); 71 // } else { 72 // 在數組的末尾添加一個元素 73 // data[size] = e; 74 // 添加元素以後數組長度加一 75 // size++; 76 // } 77 78 // 調用公共的方法,其實就是在數組的實際長度後面添加指定的元素的。 79 80 // 調用添加數組的方法,參數一,傳入數組實際的長度,參數二,添加的元素 81 add(size, e); 82 } 83 84 /** 85 * 在第一個位置添加元素,在所有元素前添加一個新元素 86 * 87 * @param e 88 */ 89 public void addFirst(E e) { 90 // 在數組的第一個位置添加元素 91 add(0, e); 92 } 93 94 95 /** 96 * 在第index個位置插入一個新元素e 97 * 98 * @param index 在第index個位置 99 * @param e 添加的元素內容 100 */ 101 public void add(int index, E e) { 102 // 判斷位置index是否小於0或者索引index是否大於數組的實際長度size 103 if (index < 0 || index > size) { 104 throw new IllegalArgumentException("add failed,Require index >= 0 and index <= size......."); 105 } 106 107 // 判斷實際長度size是否等於數組的長度 108 if (size == data.length) { 109 // 可以直接拋出異常 110 // throw new IllegalArgumentException("add failed,Array is full......"); 111 // 調用數組擴容的方法,擴容的長度爲元數組長度的2倍 112 resize(2 * data.length); 113 } 114 115 // 添加元素,就是在最後一個位置,將元素添加進去,即size的位置 116 // 從後向前移動,從後面的元素向後移動 117 // 如果傳入的index是size,則初始化的位置是size-1,那麼i的值大於等於傳入的index(即size的值),i遞減 118 119 // int i = size - 1是數組的實際長度的,即最後一個位置的元素 120 // i >= index,是在指定索引位置添加索引 121 // i--是爲了將前面的元素向後面移動的。 122 for (int i = size - 1; i >= index; i--) { 123 // 後一個索引位置賦予前一個索引位置的值 124 data[i + 1] = data[i]; 125 } 126 // 將元素的內容插入到數組的index索引位置 127 data[index] = e; 128 // 數組的size遞增 129 size++; 130 } 131 132 /** 133 * 私用擴容,擴容數組的長度 134 * 135 * @param newCapacity 136 */ 137 private void resize(int newCapacity) { 138 // 使用泛型創建對象,使用new Object的方法創建泛型的對象 139 E[] newData = (E[]) new Object[newCapacity]; 140 // 循環,將原數組裏面的內容放入到新數組裏面,新數組的長度爲元素組的2倍 141 for (int i = 0; i < size; i++) { 142 // 將原數組的值賦值給新數組的值 143 newData[i] = data[i]; 144 } 145 // 將原數組的值指向新數組,此操作,不影響原數組的正常使用 146 data = newData; 147 } 148 149 /** 150 * 獲取Index索引位置的元素 151 * 152 * @param index 153 * @return 154 */ 155 public E get(int index) { 156 // 如果索引index小於0或者索引的長度大於等於實際長度size,則拋出異常 157 if (index < 0 || index >= size) { 158 throw new IllegalArgumentException("add failed,Index is illegal......"); 159 } 160 // 返回指定索引位置的數組元素 161 return data[index]; 162 } 163 164 /** 165 * 獲取到動態數組的第一個元素 166 * 167 * @return 168 */ 169 public E getFirst() { 170 return get(0); 171 } 172 173 /** 174 * 獲取到數組的最後一個元素 175 * 176 * @return 177 */ 178 public E getLast() { 179 // 調用獲取元素的方法 180 // 避免使用return data[size - 1],可能會出現size=0的情況 181 return get(size - 1); 182 } 183 184 /** 185 * 修改index索引位置的元素e 186 * 187 * @param index 188 */ 189 public void set(int index, E e) { 190 // 如果索引index小於0或者索引的長度大於等於實際長度size,則拋出異常 191 if (index < 0 || index >= size) { 192 throw new IllegalArgumentException("add failed,Index is illegal......"); 193 } 194 // 則將元素放入到數組的索引index位置 195 data[index] = e; 196 } 197 198 199 /** 200 * @return 201 */ 202 @Override 203 public String toString() { 204 // 封裝數組遍歷的內容 205 StringBuilder sb = new StringBuilder(); 206 sb.append(String.format("Array : size = %d,capacity = %d\n", size, data.length)); 207 sb.append('['); 208 for (int i = 0; i < size; i++) { 209 sb.append(data[i]); 210 if (i != size - 1) { 211 sb.append(", "); 212 } 213 } 214 sb.append(']'); 215 return sb.toString(); 216 } 217 218 /** 219 * 查找數據中是否包含元素e 220 * 221 * @param e 222 * @return 223 */ 224 public boolean contains(E e) { 225 // 查看是否包含元素,進行遍歷 226 for (int i = 0; i < size; i++) { 227 // 如果數組元素等於傳入的元素e 228 if (data[i].equals(e)) { 229 // 返回true 230 return true; 231 } 232 } 233 return false; 234 } 235 236 /** 237 * 查找數組中元素e所在的索引,如果不存在元素e,則返回-1 238 * 239 * @param e 240 * @return 241 */ 242 public int find(E e) { 243 // 查看是否包含元素,進行遍歷 244 for (int i = 0; i < size; i++) { 245 // 如果數組元素等於傳入的元素e 246 if (data[i].equals(e)) { 247 // 返回該索引位置的索引 248 return i; 249 } 250 } 251 return -1; 252 } 253 254 /** 255 * 從數組中刪除index位置的元素,返回刪除的元素 256 * 257 * @param index 此參數是索引參數 258 * @return 259 */ 260 public E remove(int index) { 261 // 如果索引位置小於等於0或者索引位置大於等於數組的實際長度size 262 if (index < 0 || index >= size) { 263 throw new IllegalArgumentException("remove failed,Index is illegal......"); 264 } 265 266 // 返回刪除的元素,先獲取到要刪除的元素 267 E result = data[index]; 268 // System.out.println(result); 269 270 // 初始化值是要刪除索引的位置加1,且i的值小於實際size的大小,i遞減 271 272 // int i = index + 1,傳入進去的刪除索引位置的元素 273 // i < size,i小於數組的實際長度 274 // i++,i遞增 275 for (int i = index + 1; i < size; i++) { 276 // 將數組元素的值賦值被刪除元素的位置上面 277 // 即將數組元素向前移動,即第i位置的索引的數據移動到第i-1位置索引的數據 278 data[i - 1] = data[i]; 279 } 280 // 刪除元素以後,數組長度size遞減1 281 size--; 282 // 將不可訪問的位置置空 283 data[size] = null; 284 285 // 避免出現複雜度震盪 286 // 刪除數組長度,縮小容量 287 // data.length / 2 != 0,避免出現創建數組長度爲0的數組 288 if (size == data.length / 4 && data.length / 2 != 0) { 289 // 縮容數組的長度 290 resize(data.length / 2); 291 } 292 return result; 293 } 294 295 /** 296 * 刪除數組的第一個元素的值 297 * <p> 298 * 從刪除中刪除第一個元素,返回刪除的元素 299 * 300 * @return 301 */ 302 public E removeFirst() { 303 // 刪除數組的第一個位置的元素 304 return remove(0); 305 } 306 307 /** 308 * 從數組中刪除最後一個元素,返回刪除的元素。 309 * 310 * @return 311 */ 312 public E removeLast() { 313 // 刪除數組最後一個位置的元素 314 return remove(size - 1); 315 } 316 317 /** 318 * 從數組中刪除元素e 319 * 320 * @param e 321 */ 322 public void removeElement(E e) { 323 // 查看數組裏面是否有該元素 324 int index = find(e); 325 // 如果查找到存在該元素 326 if (index != -1) { 327 // 調用刪除數組元素的方法 328 remove(index); 329 } 330 } 331 332 public static void main(String[] args) { 333 // 數組添加元素 334 Array<Integer> array = new Array<>(20); 335 for (int i = 0; i < 10; i++) { 336 array.addLast(i); 337 } 338 339 System.out.println(array.toString()); 340 341 // 在指定位置添加元素 342 array.add(1, 110); 343 System.out.println(array.toString()); 344 345 // 在第一個位置添加元素 346 array.addFirst(-1); 347 System.out.println(array.toString()); 348 349 // 修改index索引位置的元素e 350 array.set(1, 120); 351 System.out.println(array.toString()); 352 353 // 是否包含某個元素 354 boolean contains = array.contains(9); 355 System.out.println(contains); 356 357 // 刪除指定索引位置的元素 358 array.remove(2); 359 System.out.println(array); 360 361 // 刪除第一個索引位置的元素 362 array.removeFirst(); 363 System.out.println(array); 364 365 // 刪除最後一個位置的元素 366 array.removeLast(); 367 System.out.println(array); 368 369 // 從數組中刪除元素e 370 array.removeElement(110); 371 System.out.println(array); 372 } 373 374 }
3、使用泛型,可以接受任何數據類型的。聲明隊列的接口。
1 package com.queue; 2 3 /** 4 * 5 */ 6 public interface Queue<E> { 7 8 /** 9 * 向隊列中添加一個元素,入隊。對應棧的入棧。 10 * 11 * @param e 12 */ 13 public void enqueue(E e); 14 15 /** 16 * 從隊列中取出一個元素,出隊。對應棧的出棧。 17 * 18 * @return 19 */ 20 public E dequeue(); 21 22 /** 23 * 獲取到隊列中隊首的元素。對應棧的查看棧頂的元素。 24 * 25 * @return 26 */ 27 public E getFront(); 28 29 /** 30 * 獲取到隊列的大小 31 * 32 * @return 33 */ 34 public int getSize(); 35 36 /** 37 * 判斷隊列是否爲空 38 * 39 * @return 40 */ 41 public boolean isEmpty(); 42 43 }
創建實現Queue自定義接口隊列的類,QueueStack隊列,結合創建的Array<E>動態數組來實現棧的入隊,出隊,查看隊首元素,判斷隊列是否爲空等等操作。
1 package com.queue; 2 3 import com.company.Array; 4 5 /** 6 * 隊列是一種先進先出的數據結構(或者稱爲先到先得),First In First Out(簡稱FIFO)。 7 * <p> 8 * <p> 9 * 1、public void enqueue(E e)入隊方法,時間複雜度0(1),均攤時間複雜度。 10 * 2、public E dequeue()出隊方法,時間複雜度0(n)。因爲隊首元素拿出去以後,後面所有元素前移一位。 11 * 如果數據量很大,這回造成執行很慢,使用循環隊列可以使時間複雜度變成O(1)。 12 * 3、public E getFront()獲取隊首方法,時間複雜度0(1)。 13 * 4、public int getSize()獲取隊列大小,時間複雜度0(1)。 14 * 5、public boolean isEmpty()獲取隊列是否爲空,時間複雜度0(1)。 15 * 16 * @param <E> 17 */ 18 public class ArrayQueue<E> implements Queue<E> { 19 20 // 聲明一個Array對象 21 private Array<E> array; 22 23 24 // Fn + Alt + Insert快捷鍵彈出構造函數 25 26 /** 27 * @param capacity 動態數組的容量大小 28 */ 29 public ArrayQueue(int capacity) { 30 // 31 array = new Array<>(capacity); 32 } 33 34 /** 35 * 無參的棧構造函數,創建一個默認容量大小的動態數組 36 */ 37 public ArrayQueue() { 38 array = new Array<>(); 39 } 40 41 /** 42 * 入隊 43 * 44 * @param e 45 */ 46 @Override 47 public void enqueue(E e) { 48 // 即向數組的末尾添加元素,如果動態數組容量不夠,會觸發動態數組的擴容機制 49 array.addLast(e); 50 } 51 52 /** 53 * 出隊 54 * 55 * @return 56 */ 57 @Override 58 public E dequeue() { 59 // 隊列,是先進先出的,所以出隊,是將開始的元素進行刪除即可 60 E first = array.removeFirst(); 61 return first; 62 } 63 64 /** 65 * 獲取隊首元素 66 * 67 * @return 68 */ 69 @Override 70 public E getFront() { 71 // 獲取到隊首元素 72 E first = array.getFirst(); 73 return first; 74 } 75 76 /** 77 * 查看隊列大小 78 * 79 * @return 80 */ 81 @Override 82 public int getSize() { 83 // 返回隊列的大小 84 return array.getSize(); 85 } 86 87 /** 88 * 判斷隊列是否爲空 89 * 90 * @return 91 */ 92 @Override 93 public boolean isEmpty() { 94 // 返回隊列是否爲空 95 return array.isEmpty(); 96 } 97 98 /** 99 * 獲取到隊列的容量大小 100 * 101 * @return 102 */ 103 public int getCapacity() { 104 return array.getCapacity(); 105 } 106 107 @Override 108 public String toString() { 109 StringBuilder sb = new StringBuilder(); 110 sb.append("Queue: "); 111 sb.append("front ["); 112 for (int i = 0; i < array.getSize(); i++) { 113 sb.append(array.get(i)); 114 if (i != array.getSize() - 1) { 115 sb.append(", "); 116 } 117 } 118 sb.append("] tail"); 119 return sb.toString(); 120 } 121 122 public static void main(String[] args) { 123 ArrayQueue<Integer> arrayQueue = new ArrayQueue<>(); 124 // 入隊操作 125 for (int i = 0; i < 10; i++) { 126 arrayQueue.enqueue(i); 127 System.out.println(arrayQueue); 128 } 129 130 // 出隊操作 131 arrayQueue.dequeue(); 132 System.out.println("出隊操作: " + arrayQueue); 133 134 // 獲取到隊列的大小 135 int size = arrayQueue.getSize(); 136 System.out.println("獲取到隊列的大小: " + size); 137 138 // 獲取到隊首的元素 139 Integer front = arrayQueue.getFront(); 140 System.out.println("獲取到隊首的元素: " + front); 141 142 // 判斷隊列是否爲空 143 System.out.println("判斷隊列是否爲空: " + arrayQueue.isEmpty()); 144 } 145 146 }
4、循環隊列,初始的情況下,隊列中無任何元素,front指向0位置,tail也指向0的位置。
1)、注意,front應該指向隊列的第一個元素,tail指向的位置是指隊列中最後一個元素的後一個位置。但是,當隊列整體爲空的時候,即隊列中連第一個元素都沒有的時候,此時,front和tail指向同一個位置,都是指向0的位置,即front和tail相等的時候,隊列爲空。
2)、如果隊列不爲空的時候,front和tail是不會相等的,如果此時,有一個元素入隊了,此時,只要維護tail隊尾就行了,tail指向下一次一個元素再入隊時候的位置。如果是出隊,只需要維護front即可,將front向下一個位置移動一個就行了。
3)、循環隊列,如果出現出隊操作,不再要求所有的元素都進行移動了,只需要front的指向改變即可,時間複雜度就變成了O(1)的操作。
4)、循環隊列,如果隊列的隊尾tail移動到最後一個位置的時候,如果隊列的隊首front前面還有空閒的位置,那麼隊列的隊尾tail可以指向隊列的隊首front的前面的位置。此時,隊列可以看成是一個環形。
5)、front和tail相等的時候,隊列爲空。所以隊列的隊首front和隊列的隊尾tail之間會存在一個空閒的位置,是無法被填寫元素的。隊列的隊滿是tail + 1 == front,表示隊列的隊滿,準確的說,是(tail + 1) % c == front表示隊列隊滿了。
6)、tail指向的位置是指下一次有元素入隊應該放入的位置,一旦有一個新的元素放入了,tail就應該加一。
7)、循環隊列中,在capacity容量中,浪費一個空間。如果只剩下一個空間的時候,循環隊列就已經滿了,就可以進行擴容了。
1 package com.queue; 2 3 /** 4 * 循環隊列 5 * 6 * @param <E> 7 */ 8 public class LoopQueue<E> implements Queue<E> { 9 10 private E[] data;//創建一個E類型的數組。 11 private int front;//定義一個變量,表示隊首指向的索引位置,指向隊首所在的索引。 12 private int tail;//定義一個變量,隊列最後一個元素下一個位置,新元素入隊存放的位置對應的索引。 13 private int size;//隊列裏面有多少個元素。 14 15 /** 16 * 創建一個含參構造函數 17 * 18 * @param capacity 數據的容量大小,用戶期望的循環隊列的容量大小 19 */ 20 public LoopQueue(int capacity) { 21 // 創建一個E類型的數組data 22 // 由於循環隊列,需要浪費一個空間,所以容量大小是用戶期望的容量大小加一。 23 data = (E[]) new Object[capacity + 1]; 24 // 成員變量初始化大小 25 front = 0;//指向隊首所在的索引爲0 26 tail = 0;//隊列最後一個元素下一個位置的索引爲0 27 size = 0;//循環隊列的大小爲0 28 } 29 30 /** 31 * 創建一個無參的構造函數,初始化循環隊列的容量爲10 32 */ 33 public LoopQueue() { 34 // 初始化容量爲10的循環隊列 35 this(10); 36 } 37 38 /** 39 * 入隊操作 40 * 41 * @param e 42 */ 43 @Override 44 public void enqueue(E e) { 45 // 首先判斷隊列是否是滿的。 46 // 判斷的標準就是隊尾tail加一取餘循環隊列的長度即下一個tail的值等於隊首front,就表示隊列滿了。 47 // 取餘操作,是讓循環隊列的整個索引循環起來,類比鐘錶循環。 48 // 假如front是一點鐘,tail是十二點鐘,那麼十二加一,取餘十二就等於一,那麼就表示該循環隊列滿了。 49 // 因爲循環隊列要空出一個位置。 50 if ((tail + 1) % data.length == front) { 51 // 如果循環隊列滿了,進行循環隊列擴容。擴容的大小是,此時循環隊列的最多可以存放元素的個數乘以2 52 // 此處,不使用data.length乘以二,因爲data.length和循環隊列最多可以盛放的元素個數之間有一個一的差距。 53 resize(this.getCapacity() * 2); 54 } 55 56 // 此時,將要存放的元素存放到tail的位置上面。 57 data[tail] = e; 58 // 此時,因爲是在循環隊列裏面,維護一下tail的位置。 59 tail = (tail + 1) % data.length; 60 // 維護size的大小 61 size++; 62 } 63 64 /** 65 * 循環隊列進行擴容操作 66 * 67 * @param newCapacity 68 * @return 69 */ 70 private void resize(int newCapacity) { 71 // 創建一個新的數組,將之前的元素放入到新的數組裏面 72 // 由於循環隊列,需要浪費一個空間,所以容量大小是用戶期望的容量大小加一。 73 E[] newData = (E[]) new Object[newCapacity + 1]; 74 75 // 將之前的數組的所有元素,放入到新的數組裏面 76 for (int i = 0; i < size; i++) { 77 // 將之前的數組的所有元素放入到新的數組的從零到size減一索引的位置上面。 78 // 在之前的data數組裏面,front隊首元素有可能不是在零索引位置上面的,比如出隊操作。 79 // 此時,將data數組裏面front隊首元素放到新的數組裏面的零索引的位置上面。 80 // 此時newData[i]的位置不是對應data[i]的位置。 81 // 因爲newData[0]對應的就是data[front],那麼newData[1]對應的就是data[front + 1],以此類推。 82 // 所以說,newData[i]對應的是data[(i + front) % data.length] 83 // data中的所有元素相對於newData中的所有元素索引值有一個(i + front)偏移的。 84 // 由於整個隊列是循環隊列,所以隊列要循環起來,(i + front)的值有可能會超過data的length長度,產生越界。 85 // 所以可以進行取餘數據長度操作。 86 newData[i] = data[(i + front) % data.length]; 87 } 88 89 // 將原來的數組data指向擴容以後的新數組newData 90 data = newData; 91 // 此時隊首front變成了0 92 front = 0; 93 // 隊尾tail變成了size,循環隊列裏面的元素個數不需要改變 94 tail = size; 95 } 96 97 /** 98 * 出隊操作 99 * 100 * @return 101 */ 102 @Override 103 public E dequeue() { 104 // 首先,判斷隊列是否爲空,如果爲空,直接拋出異常 105 if (this.isEmpty()) { 106 throw new IllegalArgumentException("Cannot dequeue from an empty queue."); 107 } 108 109 // 否則,如果此時隊列不爲空,就進行出隊操作 110 // 首先,對要出隊的元素進行保存 111 E result = data[front]; 112 // 將出隊的元素的位置指向null。 113 data[front] = null; 114 115 // 維護front,因爲是循環隊列 116 front = (front + 1) % data.length; 117 118 // 維護size的大小,由於是出隊,所以size的大小減一 119 size--; 120 121 // 出隊,可以進行擴容操作,節約資源。如果size大小等於容量的四分之一的時候,就縮容到之前的二分之一 122 // 並且縮容的值不等於0 123 if (size == this.getCapacity() / 4 && this.getCapacity() / 2 != 0) { 124 this.resize(this.getCapacity() / 2); 125 } 126 127 // 返回出隊的元素內容 128 return result; 129 } 130 131 /** 132 * 查看循環隊列的隊首元素 133 * 134 * @return 135 */ 136 @Override 137 public E getFront() { 138 // 首先,判斷隊列是否爲空,如果爲空,直接拋出異常 139 if (this.isEmpty()) { 140 throw new IllegalArgumentException("Cannot dequeue from an empty queue."); 141 } 142 return data[front]; 143 } 144 145 /** 146 * 獲取到循環隊列的大小 147 * 148 * @return 149 */ 150 @Override 151 public int getSize() { 152 // 由於size就是維護的循環隊列的大小 153 return size; 154 } 155 156 /** 157 * 判斷循環隊列是否爲空 158 * 159 * @return 160 */ 161 @Override 162 public boolean isEmpty() { 163 // 循環隊列的隊首front等於循環隊列的隊尾指向的下一個位置的tail相等的時候,即循環隊列爲空 164 return front == tail; 165 } 166 167 /** 168 * 返回循環隊列的容量大小,初始化的時候容量加一,此時獲取到循環隊列容量的時候,記得減一。 169 * 170 * @return 171 */ 172 public int getCapacity() { 173 // 擴容的時候,data發生變化,那麼擴容以後的data.length的長度就發生了變化 174 return data.length - 1; 175 } 176 177 @Override 178 public String toString() { 179 // 封裝數組遍歷的內容 180 StringBuilder sb = new StringBuilder(); 181 sb.append(String.format("LoopQueue : size = %d,capacity = %d\n", size, this.getCapacity())); 182 sb.append("front ["); 183 // 切記,i的初始化值是front。 184 // i的最大值是不可以取到tail的值的。 185 // i遞增是(i + 1) % data.length。因爲是循環隊列。 186 for (int i = front; i != tail; i = (i + 1) % data.length) { 187 sb.append(data[i]); 188 // 如果當前的索引不是最後一個元素的時候 189 if ((i + 1) % data.length != tail) { 190 sb.append(", "); 191 } 192 } 193 sb.append(" ] tail "); 194 return sb.toString(); 195 } 196 197 public static void main(String[] args) { 198 LoopQueue<Integer> loopQueue = new LoopQueue<>(); 199 // 入隊操作 200 for (int i = 0; i < 20; i++) { 201 loopQueue.enqueue(i); 202 System.out.println(loopQueue.toString()); 203 } 204 205 System.out.println(); 206 // 出隊操作 207 loopQueue.dequeue(); 208 System.out.println("循環隊列出隊操作: " + loopQueue); 209 210 // 獲取到隊列的大小 211 int size = loopQueue.getSize(); 212 System.out.println("獲取到循環隊列的大小: " + size); 213 214 // 獲取到隊首的元素 215 Integer front = loopQueue.getFront(); 216 System.out.println("獲取到循環隊列隊首的元素: " + front); 217 218 // 判斷隊列是否爲空 219 System.out.println("判斷循環隊列是否爲空: " + loopQueue.isEmpty()); 220 } 221 222 }
執行效果,如下所示:
5、數組隊列和循環隊列的比較,性能測試。
1 package com.queue; 2 3 import java.util.Random; 4 5 /** 6 * 7 */ 8 public class Main { 9 10 /** 11 * 測試使用queue運行opCount個enqueue和dequeue操作所需要的時間,單位:秒 12 * 13 * @param queue 14 * @param opCount 15 * @return 16 */ 17 public static double queuePerforms(Queue<Integer> queue, int opCount) { 18 // 開始時間 19 long startTime = System.nanoTime(); 20 21 Random random = new Random(); 22 // 入隊操作 23 for (int i = 0; i < opCount; i++) { 24 queue.enqueue(random.nextInt(Integer.MAX_VALUE)); 25 } 26 27 // 出隊操作 28 for (int i = 0; i < opCount; i++) { 29 queue.dequeue(); 30 } 31 32 // 結束時間 33 long endTime = System.nanoTime(); 34 35 // 秒與納秒之前差九位數 36 return (endTime - startTime) / 1000000000.0; 37 } 38 39 public static void main(String[] args) { 40 int opCount = 1000000;// 一百萬次 41 42 // 數組隊列的性能 43 // 影響數組隊列性能的是出隊操作,因爲每一個元素都要進行前移操作 44 ArrayQueue<Integer> arrayQueue = new ArrayQueue<>(); 45 double time1 = queuePerforms(arrayQueue, opCount); 46 System.out.println("ArrayQueue, time: " + time1 + " s"); 47 48 49 // 循環隊列的性能 50 LoopQueue<Integer> loopQueue = new LoopQueue<>(); 51 double time2 = queuePerforms(loopQueue, opCount); 52 System.out.println("LoopQueue, time: " + time2 + " s"); 53 } 54 55 }
作者:別先生
博客園:https://www.cnblogs.com/biehongli/
如果您想及時得到個人撰寫文章以及著作的消息推送,可以掃描上方二維碼,關注個人公衆號哦。