題目連結:
題目意譯:
設計你自己的環形佇列之實作。環形佇列為一個線性資料結構其中操作是基於 FIFO(First In First Out,先進先出)之準則且最後的位置是接回到第一個位置形成了一個圓圈。因此又被稱為「環形緩衝區」。
環形佇列的其中一個好處是我們可以善加利用佇列前方的空間。在正常的佇列中,一旦佇列滿了,即便佇列前方仍有空間我們依舊無法插入下一個元素。但是當使用環形佇列時,我們便可以使用那些空間去儲存新的值。
實作 MyCircularQueue 類別:
MyCircularQueue(k) 初始化物件使得佇列大小為 k。
int Front() 取得佇列的開頭元素。如果佇列為空,則回傳 -1 。
int Rear() 取得佇列的結尾元素。如果佇列為空,則回傳 -1 。
boolean enQueue(int value) 插入一個元素進環形佇列。回傳真(True)如果操作成功的話。
boolean deQueue() 從環形佇列中刪除一個元素。回傳真,如果操作成功的話。
boolean isEmpty() 檢查環形佇列是否為空。
boolean isFull() 檢查環形佇列是否滿了。
限制:
1 ≦ k ≦ 1000
0 ≦ value ≦ 1000
最多 3000 次呼叫為 enQueue 、 deQueue 、 Front 、 Rear 、 isEmpty 以及 isFull。
進階: 你可以不使用任何內建的佇列解出這題嗎?
範例測資:
輸入:
["MyCircularQueue", "enQueue", "enQueue", "enQueue", "enQueue", "Rear", "isFull", "deQueue", "enQueue", "Rear"]
[[3], [1], [2], [3], [4], [], [], [], [4], []]
輸出:
[null, true, true, true, false, 3, true, true, true, 4]
解釋:
MyCircularQueue myCircularQueue = new MyCircularQueue(3);
myCircularQueue.enQueue(1); // 回傳真
myCircularQueue.enQueue(2); // 回傳真
myCircularQueue.enQueue(3); // 回傳真
myCircularQueue.enQueue(4); // 回傳假
myCircularQueue.Rear(); // 回傳 3
myCircularQueue.isFull(); // 回傳真
myCircularQueue.deQueue(); // 回傳真
myCircularQueue.enQueue(4); // 回傳真
myCircularQueue.Rear(); // 回傳 4
解題思維:
環形佇列基本上是一個陣列,其頭尾是相鄰的。
我們可以藉由兩個指標 F 、 L 用來代表佇列的前端以及尾端(不過通常不會正好是尾端,而是尾端的下一格位置,用以代表下一個元素要放的位置),還有另一個布林變數 H 用來表示佇列有沒有儲存東西。
因此,MyCircularQueue(k) 就是宣告一個大小為 k 的陣列(在此我們叫它陣列 A)、Front() 即是 A[F]、Rear() 則是 A[L - 1](不過記得還要判斷是否為空)。
isEmpty() 即是布林變數 H 的值,代表佇列有沒有東西。
isFull() 為 F == L 且 H 為真(這裡需要 H 是因為佇列為空的同時 F 也是等於 L )。
enQueue(int value) 要先判斷佇列是否滿了(如上),滿了就回傳 -1 ;反之,就將 A[L] 設為 value 、 H 設為真,並將 L 加 1。
deQueue() 要先判斷佇列是否為空,如果是空的就回傳 -1 ;沒有空就把 F 加 1,但是需要額外判斷 F 是否等於 L 因為佇列現在可能為空(所以 H 需要更新成假)。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。