定義
佇列(Queue):是隻允許在一端進行插入操作,而在另一端進行刪除操作的線性表。
佇列是一種先進先出的線性表。允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。
如下圖所示:
迴圈佇列
線性表有順序儲存和鏈式儲存,棧是線性表,所以有這兩種儲存方式。同樣,佇列作為一種特殊的線性表,也同樣存在這兩種儲存方式。
佇列順序儲存的不足
假設有一個佇列有n個元素,則順序儲存的佇列需要建立一個大於n的陣列,並把佇列的所有元素儲存在陣列的前n個單元,陣列下標為0的一端即是隊頭。所謂的入隊操作,其實就是在隊尾追加一個元素,不需要移動任何元素,因此世家複雜度為O(1)。
與棧不同的是,佇列元素的出隊是在隊頭,即下標為0的位置,也就意味著,佇列中的所有元素都得向前移動,也就是下標為0的位置不為空,時間複雜度為O(n).
它們的具體實現和線性表的順序儲存結構是一樣的,不再累贅。
但是
如果不去限制佇列的元素必須儲存在陣列的前n個單元這一條件,出隊的效能就會大大增加,如圖
為了避免只有一個元素時,隊頭和隊尾重合使得處理變得麻煩,就引入兩個指標,front指向隊頭元素,rear指向隊尾元素的下一個位置,這樣當front等於rear時,表示空佇列。
這樣又出現一個問題,如果隊尾已有元素,再插入新元素時rear指向哪裡?而且,當佇列中只有隊尾有元素時,向後再加,就會產生陣列越界錯誤,可實際上之前的位置可能有空,我們把這種現象叫做假溢位。
迴圈佇列定義
解決假溢位的辦法就是後面滿了,就再從頭開始,也就是頭尾相接的迴圈。我們把佇列的這種頭尾相接的順序儲存結構稱為迴圈佇列。
下標2、3、4位置已有元素,在插入新元素,則存放下標為0的位置。如圖:
但之前約定當front==rear時,表示佇列為空,上述方法中front==rear時還表示佇列已滿,怎麼處理呢?
我們要求,佇列滿時,陣列中還有一個空閒單元,如圖:
得出以下公式:
-
佇列滿 的條件(rear+1)%QueueSize==front
-
佇列長度公式:(rear-front+QueueSize)%QueueSize
佇列的鏈式儲存
佇列的鏈式儲存結構,其實就是線性表的單連結串列,只不過它只能尾進頭出而已,我們簡稱為鏈佇列。
空佇列時,front和rear都指向頭節點:
入隊操作
- 將最後一個元素後繼指向新元素;
- 將尾指標指向新元素。
出隊操作
- 將頭結點的後繼改為後面一位結點;
- 若除頭節點外只剩一個元素時,將rear指向頭節點。
總的來說,在可以確定佇列長度最大值的情況下,建議用迴圈佇列,如果你無法預估佇列的長度時,則用鏈佇列。
更多精彩內容,歡迎關注我的微信公眾號——Android機動車