標籤:資料結構 線性表之隊列 java實現隊列
隊列(Queue)的定義:只允許在一端進行插入另一端進行刪除操作的線性表。允許插入的一端稱為隊尾(rear) ,允許刪除的一端稱為隊頭(front)。 具有“先進先出”特點。
隊列也是線性表,所以也存在順序結構和鏈式結構。
順序隊列:
對於隊列,入隊操作的解釋為:
(是在隊尾追加一個元素,不需要移動任何元素,因此時間複雜度為0(1)。)
- 判斷隊列是否已滿;
- 如果沒滿則先給隊尾元素賦值;
- 然後將隊尾指標後移一位(對隊尾指標賦值,Q->rear = Q->rear+1 )。
出隊操作解釋為:
(隊列中的所有元素都得向前移動,以保證隊列的隊頭(也就是下標為0的位置)不為空白,此時的時間複雜度為0(n)。)
- 判斷隊列是否為空白;
- 若不為空白則將對首元素取出用來返回;
- 然後將對首指標後移一位(對隊首指標賦值,Q->front = Q->front+1 )。
- 隊列是否為空白判斷:隊首指標和隊尾指標進行判斷是否相等。
隊列的實際長度:隊尾指標-對首指標;也可以通過設定一個變數來進行儲存。
下面是我的順序隊列的Java實現:
package com.phn.queue;/** * @author 潘海南 * @Email [email protected] * @TODO 順序隊列 * @date 2015年7月20日 */public class FOArrayQueue<E> { //預設隊列容量 private static final int DEFUALT_CAPACITY = 100; //佇列儲存體資料元素的數組 private Object[] data = null; //隊列的實際大小 private int size; //隊列的對首索引 private int front; //隊列的隊尾索引 private int rear; //隊列的實際容量 private int capacity; /** * @TODO 無參建構函式,初始化隊列 */ public FOArrayQueue() { this(DEFUALT_CAPACITY); } /** * @param initialCapacity 隊列初始化容量 */ public FOArrayQueue(int initialCapacity) { this.data = new Object[initialCapacity]; this.front = 0; this.rear = 0; this.size = 0; this.capacity = initialCapacity; } /** * @TODO 隊列入隊操作 * @param e 需要入隊的資料元素 * @return true */ public boolean enQueue(E e){ if(this.isFull()){ throw new RuntimeException("隊列已滿!最大容量="+this.capacity); } this.data[this.rear] = e;// this.rear = (this.rear+1)%(this.capacity); this.rear = this.rear+1; this.size++; return true; } /** * @TODO 隊列的出隊操作 * @return e 位於對首的資料元素 */ public E deQueue(){ if(this.isEmpty()){ throw new RuntimeException("隊列為空白!"); } E e = (E)this.data[this.front];// this.front = (this.front+1)%(this.capacity); this.front = this.front+1; this.size--; return e; } /** * @TODO 判斷隊列是否為空白 * @return true空 or false不為空白 */ public boolean isEmpty(){ if(this.front==this.size){ return true; } return false; } /** * @TODO 判斷隊列是否已滿 * @return true滿 or false未滿 */ public boolean isFull(){ //這裡不能用size來進行判斷,用size會出現假溢出的情況 if(this.rear==this.capacity-1){ return true; } return false; } /** * @TODO 擷取隊列的長度 * @return size */ public int size(){ return this.size; } @Override public String toString() { StringBuffer sb = new StringBuffer("["); if(this.data[this.front]!=null){ sb.append(this.data[this.front]); for (int i = this.front+1; i < this.rear; i++) { sb.append(", "+this.data[i]); } } sb.append("]"); return sb.toString(); }}
下面是我的測試代碼:
public static void main(String[] args) { FOArrayQueue<String> foaq = new FOArrayQueue<String>(); for (int i = 1; i <= 6; i++) { foaq.enQueue("元素"+i); } System.out.println(foaq); System.out.println(foaq.size()); System.out.println(foaq.deQueue());; System.out.println(foaq); System.out.println(foaq.size());}
測試:
??由於隊列的入隊和出隊操作的結果導致隊列容易出現“假溢出”,於是乎出現了迴圈隊列。
迴圈隊列需要注意的地方如下:
- 執行入隊操作後,隊尾指標的變化:Q->rear = (Q->rear+1)% capacity。
- 執行出隊操作後,對首指標的變化:Q->front= (Q->front+1)% capacity。
- 判斷是否為空白的情況:Q->front=Q->rear。
- 判斷隊列是否為滿的情況,需要放棄隊列一個位置來區分開來隊列是否為空白是否為滿,這樣判斷條件為:Q->front= (Q->rear + 1)% capacity。
- 隊列實際長度:(隊尾指標-對首指標+數組長度)% 數組長度;或者可以通過設定一個變數來進行儲存;或者都通過Q->front=Q->rear外加一個flag變數進行判斷。
好了,迴圈隊列也就介紹這些。
鏈隊列:
定義:隊列的鏈式儲存結構,其實就是線性表的單鏈表,只不過它只能尾進頭出而已,我們把它簡稱為鏈隊列。
??為了方便操作,將隊頭指標指向鏈隊列的頭結點,而隊尾指標指向終端結點。
??當隊列為空白時,front和rear都指向頭結點。
??正如鏈隊就類似於單鏈表,這裡鏈隊的入隊、出隊、判斷為空白等操作也基本類似,這裡就不描述了,詳情請參考之前的單鏈表。
??其實看了之前的再看這裡其實很容易的,不懂的話還可以參考這個網址:http://www.nowamagic.net/librarys/veda/detail/2357
迴圈隊列和鏈隊列的比較。
- 時間上:它們的基本操作都是常數時間O(1),這裡還有點細微的差別(迴圈隊列是事先申請好空間,使用期間不釋放,而對於鏈隊列,每次申請和釋放結點也會存在一些時間開銷,如果入隊出隊頻繁,則兩者還是有細微差異)。
- 空間上:迴圈隊列的長度固定,因此有了空間浪費的問題;而鏈隊列不存在這個問題,但是每個節點需要一個指標域,這是需要消耗一定的空間。相對來說,鏈隊列更加靈活。
總結:
??在確定隊列長度最大值的情況,建議使用迴圈隊列;否則請使用鏈隊列。“迴圈隊列”最大優點就是節省空間的和少分配空間,而鏈隊列多了一點點地址儲存開銷。
著作權聲明:本文為博主原創文章,如需轉載請註明出處並附上連結,謝謝。
Java資料結構-線性表之隊列