算法:使用棧實現(xiàn)隊列

分析

棧的特性后入先出,隊列的特性是先入先出,要用棧去實現(xiàn)一個隊列,就要思考如果將一個棧轉(zhuǎn)換成隊列的特性。

舉個例子:
依次將 1、2、3、4、5入棧,出棧的話,順序應(yīng)該是:5、4、3、2、1。
依次將 1、2、3、4、5入隊,出隊的話,順序應(yīng)該是:1、2、3、4、5。

思路:其實這個問題非常簡單了,因為已經(jīng)限定了條件,只能使用棧這個數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)隊列,一個棧的話不能滿足條件,又沒有別的數(shù)據(jù)結(jié)構(gòu)來輔助,那么唯一能嘗試的辦法就是再加一個棧試試咯~

那么現(xiàn)在我們有兩個棧,分別為 inStack 和 outStack,首先inStack依次入棧1、2,然后inStack依次出棧2、1,再按照出棧順序?qū)?、1入棧outStack:2、1,有沒有發(fā)現(xiàn),outStack正好將inStack反過來,outStack的出棧順序是1、2,剛好滿足了隊列的性質(zhì)。

現(xiàn)在再來考慮出棧后再次入棧的情況:
1、2入隊,先取出隊頭1,然后入隊3,再依次全部出隊:2、3。

//  將1、2入棧inStack
inStack:top>>2>>1
outStack: top>>
// 要去修1,需要將inStack全部依次入棧outStack
inStack:top>>
outStack: top>>1>>2
// 然后從outStack棧頂出棧1
inStack:top>>
outStack: top>>2
// 現(xiàn)在需要入棧3
inStack:top>>3
outStack: top>>2
// 現(xiàn)在取出2
inStack:top>>3
outStack: top>>
//取出3需要先將inStack入棧outStack
inStack:top>>
outStack: top>>3
//outStack棧頂出棧3
inStack:top>>
outStack: top>>3

由此可見棧實現(xiàn)隊列的流程就是,入隊只需要將向inStack棧頂加入元素,出隊時,如果outStack為空,就將inStack依次出棧并入棧outStack。然后從outStack棧頂取出元素,如果outStack不為空,直接取出元素。

Java實現(xiàn)

// 用棧實現(xiàn)一個隊列

package test;

public class QueueWithStack<E> {
    // 使用兩個棧來實現(xiàn)一個隊列
    // 入隊時,向inStack入棧一個元素
    private Stack<E> inStack = new Stack<E>();
    // 出隊時,從outStack出棧一個元素
    private Stack<E> outStack = new Stack<E>();
    
    // 關(guān)鍵邏輯,當需要出隊或者查看隊頭元素時,先查看outStack是否有值,第一次肯定是空的
    // 這時將inStack的元素全部依次出棧并入棧到outStack后,outStack就是反向放置了inStack的元素
    // 此時outStack出棧的元素順序剛好就是之前inStack的入棧順序
    // 當需要出隊時,如果outStack不為空,那么直接從outStack出棧
    private void checkStack() {
        if (outStack.isEmpty()) {
             while(inStack.isEmpty() == false) {
                 outStack.push(inStack.pop());
             }
        } 
    }

    // 兩個棧的數(shù)據(jù)數(shù)量相加是隊列的數(shù)據(jù)數(shù)量
    public int sise() {
        return inStack.size() + outStack.size();
    }
    
    // 兩個棧都為空隊列為空
    public boolean isEmpty() {
        return inStack.isEmpty() && outStack.isEmpty();
    }
    
    // 入隊就是在鏈表尾部添加元素
    public void enQueue(E element) {
        inStack.push(element);
    }
    
    // 出隊就是刪除鏈表頭部元素
    public E deQueue() {
        checkStack();
        return outStack.pop();
    }
    
    // 獲取隊頭就是獲取鏈表頭部元素
    public E front() {
        checkStack();
        return outStack.peek();
    }
}

其他語言

很多語言不像Java直接有Stack這種包裝好的對象來實現(xiàn)一個棧或者隊列的數(shù)據(jù)結(jié)構(gòu)的功能,不過這也不妨礙在其他語言來實現(xiàn)這個功能。
棧和隊列本質(zhì)上就是一個弱化了功能的可以動態(tài)添加和刪除元素的數(shù)組,對外隱藏了可以通過下標向任意位置插入和取出元素的接口,只能操作頭尾。
入棧是向隊列尾部添加一個元素,出棧是移除隊列尾部的元素。
入隊是向隊列尾部添加一個元素,出隊是移除隊列頭部的元素。
Objective-C模擬一個棧:

// 初始化一個棧
NSMutableArray *stack = [NSMutableArray array];
// 入棧
[stack addObject:root];
// 獲取棧頂元素
id top = [stack lastObject];
// 出棧
[stack removeLastObject];

Objective-C模擬一個隊列:

// 初始化一個隊列
NSMutableArray *queue = [NSMutableArray array];
// 入隊
[queue addObject:root];
// 獲取隊頭元素
id top = [queue firstObject];
// 出隊
[queue removeObjectAtIndex:0];

通過上面這些代碼,Objective-C也可以模擬完成上面的算法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容