數據結構之隊列

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/

如果您想及時得到個人撰寫文章以及著作的消息推送,可以掃描上方二維碼,關注個人公衆號哦。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章