由兩個棧組成的隊列,你玩過嘛?

題目描述

【題目】:
編寫一個類,用兩個棧實現隊列,滿足隊列的基本操作要求:enqueue(入隊)、出隊(dequeue),peek:獲取隊列中對頭元素。

【解答】

  1. 棧數據結構的特點是先進後出,而隊列數據結構的特點是先進先出。用兩個棧正好能把順序反過來實現類似隊列的操作。
  2. 具體實現上是一個棧作爲壓入數據棧,在壓入數據棧時,只往這個棧中壓入數據(入隊),記爲 stackPush,另一個棧只作爲彈出棧,在彈出數據(出隊)只從這個棧彈出,記爲 stackPop。
  3. 因爲數據壓入棧的時候,順序時先進後出的。那麼只要把 stackPush 的數據再壓入 stackPop 中,順序就變回來了。

【舉個栗子】
把 1~5 依次壓入 stackPush ,那麼從stackPush 的棧頂的棧底爲 5~1 ,此時再將 5~1 倒stackPop,那麼從 stackPop 的棧頂到棧底就變成了 1~5.再從 stackPop 彈出時,順序就像隊列一樣,如圖所示:

 

聽起來貌似簡單,但實際上必須做到以下兩點:
1.如果 stackPush 要往 stackPop 中壓入數據,那麼必須一次性把 stackPush 中的數據全部壓入。
2.如果 stackPop 不爲空,stackPush 絕對不能向 stackPop 中壓入數據。

違反了以上兩點,都會發生錯誤。

  • 違反 1 的情況舉例:1~5 依次次壓入stackPush,stackPush 的棧頂到棧底爲 5~1,從 stackPush 壓入 stackPop 時,如果只將 5 和 4 壓入了 stackPop ,stackPush 還剩下 1、2、3 沒有壓入。此時如果用戶想進行出隊操作,那麼 4 將最先彈出,與預想的隊列順序就不一致。
  • 違反 2 的情況舉例:1~5 依次壓入 stackPush,將 stackPush 中的所有數據壓入了 stackPop ,此時從 stackPop 棧頂到棧底爲 1~5。此時,又有 6~10 壓入 stackPop ,這時候stackPop 不爲空不能壓入數據,如果違反2,向 stackPop 壓入數據,stackPop 棧頂到棧底爲 6~10,1~5,此時用戶如果想進行出隊操作,那麼 6 將最先彈出,又與預想的隊列順序不一致。

代碼實現

上述介紹了壓入數據的注意事項。具體實現參看如下代碼:

 1public class TwoStackQueue {
 2    private Stack<Integer> stackPush;
 3    private Stack<Integer> stackPop;
 4
 5    public TwoStackQueue() {
 6        stackPush = new Stack<Integer>();
 7        stackPop = new Stack<Integer>();
 8    }
 9
10    //TODO:入隊操作,往隊列中添加數據
11    public void enqueue(int newData) {
12        this.stackPush.push(newData);
13    }
14
15    //TODO:出隊操作,從隊列中獲取數據,注意隊列數據結構是先進先出
16    public int dequeue() {
17        if (stackPush.empty() && stackPop.empty()) {
18            throw new RuntimeException("Queue is empty!");
19        } else if (stackPop.empty()) {
20            while (!stackPush.empty()) {
21                this.stackPop.push(this.stackPush.pop());
22            }
23        }
24        return stackPop.pop();
25    }
26
27    //TODO:獲取隊列中的隊頭元素
28    public int peek() {
29        if (stackPush.empty() && stackPop.empty()) {
30            throw new RuntimeException("Queue is  empty!");
31        }else if (stackPop.empty()) {
32            while (!stackPush.empty()) {
33                this.stackPop.push(this.stackPush.pop());
34            }
35        }
36        return stackPop.peek();
37    }
38}

本段代碼是在在調用 dequeue 和 peek 方法時進行壓入數據的過程。這個壓入數據的操作選擇的時機可以有很多,調用 enqueue、dequeue 和 peek 三種方法中的任何一種時發生壓入數據的行爲都是可以的。只要不違反上述兩點,就不會出錯。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章