功能需求
在一個類中,定義兩個公共訪問的棧,這兩個棧通過交互形成一個隊列,保持先進先出的特點並且支持入棧add、poll、peek的操作。同時算法複雜度不能太高。
詳細解析
棧的特點是先進後出,而隊列的特點是先進先出,我們把兩個棧首尾相接起來,一個壓入棧,一個彈出棧,就可以實現相應的隊列的操作。具體實現是定義一個壓入棧stackPush,在壓入數據時只往這個棧中壓入數據和一個退出棧stackPop彈出數據只從這個棧中彈出,分別對應隊列的入列和出列。
因爲數據壓入棧的時候,順序是先進後出的。那麼只要吧stackPush的數據在壓入stackPop中,順序就變了回來。例如,將1~5依次壓入stackPush棧中,那麼在stackPush棧中棧頂到棧底依次爲5~1,將此時的5~1倒入stackPop中,那麼stackPop棧中從棧頂到棧底的數據就會依次是1~5.再從stackPop彈出時,就會像隊列一樣,其效果圖如下
這樣看起來是非常簡單的,實際上的要求將會有以下兩點:1、stackPush中的數據必須要一次性全部壓入stackPop中;2、如果stackPop棧中已經存在元素數據,是不能給stackPop棧中壓入數據的。這兩點都是會導致錯誤的。
如果違反了1原則:舉個例子,1~5依次壓入stackPush,stackPush棧頂到棧底的元素分別爲5~1,從stackPush壓入stackPop棧中時,只將棧頂的5和4壓入stackPop,stackPush棧還有3,2,1三個元素存在沒有壓入。此時用戶想要彈棧操作,那麼4將先被彈出。這樣與預想的隊列順序就不一致了。
如果違反了規則2:將1-5依次壓入stackPush棧中,stackPush棧中從棧頂到棧底依次爲5~1,stackPush棧中的元素全部倒入stackPop棧中壓棧處理,所以stackPop棧中的元素從棧頂到棧底依次爲1~5,又在此時壓入6~10到stackPush,stackPop不爲空,stackPush不能將其數據壓入stackPop。如果違反了強行壓入,那麼stackPop棧中從棧頂到棧低的元素就會變爲6~10,1~5,那麼此時再彈出棧中元素就會把6先彈出棧,不符合隊裏的規則。
在調用add(), poll(),peek三種方法中任何一種發生時"壓入"元素時的行爲都是可以的,前提條件是不違反以上兩點。具體請看以下代碼:
代碼實現
package com.hekaikai666.test2;
import java.util.Stack;
/**
*
* @author hekaikai666
* @time 2018年8月23日下午8:40:35
**/
public class StackTo {
// 棧一存儲數據
private Stack<Integer> stackPush;
// 棧二存儲棧一中出來的數據
private Stack<Integer> stackPop;
/**
* 單例模式實例化棧(構造方法)
*/
public StackTo() {
super();
this.stackPush = new Stack<Integer>();
this.stackPop = new Stack<Integer>();
}
/**
* poll()方法操作棧中數據
*/
public int poll() {
// 判斷兩個棧是否都爲空
if (stackPop.isEmpty() && stackPush.isEmpty()) {
// 拋出一個運行時異常
throw new RuntimeException("Your Stack is empty");
// 如果只有存入棧爲空
} else if (stackPop.isEmpty()) {
// 循環彈出stackPush中的元素並壓入stackPop棧中,知道stackPush棧爲空
while (!stackPush.isEmpty()) {
stackPop.push(stackPush.pop());
}
}
// 返回此棧值
return stackPop.pop();
}
public int peek() {
// 判斷兩個棧是否都爲空
if (stackPop.isEmpty() && stackPush.isEmpty()) {
// 拋出一個運行時異常
throw new RuntimeException("Your Stack is empty");
// 如果只有存入棧爲空
} else if(stackPop.isEmpty()) {
// 循環彈出stackPush中的元素並壓入stackPop棧中,知道stackPush棧爲空
while (!stackPush.isEmpty()) {
stackPop.push(stackPush.pop());
}
}
// 返回此棧值
return stackPop.peek();
}
}
總結分析
我們都能想到兩個先進先出的棧首尾相接能實現一個隊列,但是在這兩個棧中的細節,比如說他們要是沒有完全彈出元素,那麼會導致棧種元素混亂,之後就不符合隊列的要求了,其實實現很簡單,思想很重要