標籤:
什麼是隊列:
隊列(queue)是只允許在一端進行插入操作,而在另一端進行刪除操作的線性表。隊列是一種先進先出(First In First Out)的線性表,簡稱FIFO。允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。
隊列的基本操作:
enqueue(Object obj):入隊操作
dequeue():出隊操作
迴圈隊列:
由於隊列如果做成數組的形式,為了保證出隊列的時間複雜度為O(1),所以不能將數組中的元素進行移動(如果移動,時間複雜度就變為了O(n))。因此前面出棧之後的元素空間就會被浪費。所以我們將數組的頭尾進行相接,這樣就形成了迴圈,我們稱這樣的隊列為迴圈隊列。結構圖如下所示:
判斷隊列為空白:front指標指向隊頭元素,rear指標指向隊尾元素的下一個位置,這樣的front等於rear的時候,此時隊列不是還剩下一個元素,而是為空白隊列。所以空隊列的判斷為front == rear。
判斷隊列為滿:當隊列為滿時,我們修改其條件,儲存一個元素空間。也就是說,隊列為滿時,數組中還有一個空閑單元。(這就是為什麼後面的代碼中數組的大小為5,卻最多可以插入4個元素)所以滿隊列的判斷為(rear+1)%QueueSize == front。
程式碼範例如下:
package queue;/** * 數組中只儲存數組大小-1個元素, * 保證rear轉一圈之後不會和head相等, * 也就是隊列滿的時候,rear+1=head, * 中間剛好空一個元素。 * 當rear=head的時候,一定是隊列空了。 * */public class QueueArray {private Object[] objs;private int front;private int rear;public QueueArray(){this(10);}public QueueArray(int size){objs = new Object[size];front = 0;rear = 0;}public boolean enqueue(Object obj){//判斷隊列是否為滿if((rear+1)%objs.length == front){return false;}objs[rear] = obj;rear = (rear+1)%objs.length;return true;}public Object dequeue(){//判斷隊列是否為空白if(rear == front){return null;}Object obj = objs[front];front = (front+1)%objs.length;return obj;}public void traverse(){while(front != rear){System.out.print(objs[front]+" ");front = ((front+1)%objs.length);}}public static void main(String[] args) {QueueArray q = new QueueArray(5);q.enqueue("A");q.enqueue("B");q.enqueue("C");System.out.println("刪除的元素為:"+q.dequeue());q.enqueue("F");System.out.println("刪除的元素為:"+q.dequeue());q.traverse();}}隊列的鏈式儲存方式:
入隊與出隊結構圖:
入隊:將新節點作為原來節點的後繼,再將新節點設定為尾節點。this.rear.next = newNode; this.rear = newNode;
出隊:將需要刪除節點的後繼直接賦值給頭結點的後繼即可。this.front.next = node.next;
具體程式碼範例如下:
package queue;public class LinkQueue<T> {private class Node{private T data;private Node next;public Node(){}}private Node front;private Node rear;private int count;//隊列中元素的數量public LinkQueue(){Node p = new Node();p.data = null;p.next = null;front = rear = p;}//使用尾插法插入資料public void equeue(T item){Node newNode = new Node();newNode.data = item;newNode.next = null;this.rear.next = newNode;this.rear = newNode;count++;}public T dequeue() throws Exception{if(isEmpty()){throw new Exception("隊列為空白!");}T obj;Node node = this.front.next;obj = node.data;this.front.next = node.next;if(rear == node){rear = front;}count --;return obj;}public int size(){return count;}public boolean isEmpty(){return front == rear;}public void traverse(){Node current = front.next;while(current != null){System.out.println(current.data);current = current.next;}}public static void main(String[] args) throws Exception {LinkQueue<String> lq = new LinkQueue<String>();lq.equeue("A");lq.equeue("B");lq.equeue("C");lq.equeue("D");lq.traverse();System.out.println("隊列的長度為:"+lq.size());System.out.println("刪除的元素為:"+lq.dequeue());lq.traverse();}}無論是迴圈隊列還是鏈式隊列,從時間上看基本都是常數的時間,即時間複雜度都為O(1)。不過迴圈隊列是事先申請好了空間,使用期間不釋放。而對於鏈式隊列,每次申請或釋放節點也會存在一定的開銷,如果入隊或出隊頻繁,則還是存在細微的差異,但是鏈式隊列在空間上更加靈活。所以,在可以確定隊列長度最大值的情況下,建議用迴圈隊列,如果無法預估隊列的長度,則使用鏈隊列。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
java語言實現隊列