Java數據結構-線性表之隊列

隊列(Queue)的定義:只允許在一端進行插入另一端進行刪除操作的線性表。允許插入的一端稱爲隊尾(rear) ,允許刪除的一端稱爲隊頭(front)。 具有“先進先出”特點。

隊列也是線性表,所以也存在順序結構和鏈式結構。

順序隊列:

對於隊列,入隊操作的解釋爲:
(是在隊尾追加一個元素,不需要移動任何元素,因此時間複雜度爲0(1)。)

  1. 判斷隊列是否已滿;
  2. 如果沒滿則先給隊尾元素賦值;
  3. 然後將隊尾指針後移一位(對隊尾指針賦值,Q->rear = Q->rear+1 )。

出隊操作解釋爲:
(隊列中的所有元素都得向前移動,以保證隊列的隊頭(也就是下標爲0的位置)不爲空,此時的時間複雜度爲0(n)。)

  1. 判斷隊列是否爲空;
  2. 若不爲空則將對首元素取出用來返回;
  3. 然後將對首指針後移一位(對隊首指針賦值,Q->front = Q->front+1 )。
  4. 隊列是否爲空判斷:隊首指針和隊尾指針進行判斷是否相等。

隊列的實際長度:隊尾指針-對首指針;也可以通過設定一個變量來進行存儲。

下面是我的順序隊列的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

循環隊列和鏈隊列的比較。

  1. 時間上:它們的基本操作都是常數時間O(1),這裏還有點細微的差別(循環隊列是事先申請好空間,使用期間不釋放,而對於鏈隊列,每次申請和釋放結點也會存在一些時間開銷,如果入隊出隊頻繁,則兩者還是有細微差異)。
  2. 空間上:循環隊列的長度固定,因此有了空間浪費的問題;而鏈隊列不存在這個問題,但是每個節點需要一個指針域,這是需要消耗一定的空間。相對來說,鏈隊列更加靈活。

總結:
  在確定隊列長度最大值的情況,建議使用循環隊列;否則請使用鏈隊列。“循環隊列”最大優點就是節省空間和少分配空間,而鏈隊列多了一點點地址存儲開銷。

發佈了83 篇原創文章 · 獲贊 13 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章