分析
棧的特性后入先出,隊列的特性是先入先出,要用棧去實現(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也可以模擬完成上面的算法。