棧的簡單應用——中綴表示式與字尾表示式
中綴表示式:(1+((2+3)*(4*5)))
E.W.Dijkstra雙棧演算法
1.將運算元壓入運算元棧。
2.將運算子壓入運算子棧。
3.忽略左括號。
4.在遇到右括號時,彈出一個運算子,彈出所需數量的操縱數,並將運算子和運算元的運算結果壓入運算元棧。
public static void main(String[] args) {
Stack<String> ops = new Stack<String>();
Stack<Double> vals = new Stack<Double>();
while(!StdIn.isEmpty()) {
String s=StdIn.readString();
if (s.equals("(")) ;
else if (s.equals("+")) ops.push(s);
else if (s.equals("-")) ops.push(s);
else if (s.equals("*")) ops.push(s);
else if (s.equals("/")) ops.push(s);
else if (s.equals("sqrt")) ops.push(s);
else if (s.equals(")")) {
String op = ops.pop();
double v = vals.pop();
if (op.equals("+")) v = vals.pop() + v;
else if (op.equals("-")) v = vals.pop() - v;
else if (op.equals("*")) v = vals.pop() * v;
else if (op.equals("/")) v = vals.pop() / v;
else if (op.equals("sqrt")) v = Math.sqrt(v);
vals.push(v);
}
else vals.push(Double.parseDouble(s));
}
StdOut.println(vals.pop());
}
演算法是程式碼參考Robert Sedgewick的Algorithms 4th Edition下壓棧部分,之後想著用他給出的Stack類來實現字尾表示式。
字尾表示式:1 3 2 - 4 5 * * +
字尾表示式是兩個運算元後面加一運算子,上面表示式即 1 ( (3 2 -)(4 5 *) *) +
此時的思路並非仍是建立雙棧來壓入和彈出進行運算,而是壓入運算元後一碰到後面緊跟運算子直接進行運算,再壓入運算元棧,但是要注意的是彈出運算元時運算先彈出的是減數或除數(加和乘便不用考慮彈出順序)。
public static void main(String[] args) {
Stack<Double> vals = new Stack<Double>();
double v=0;
while(!StdIn.isEmpty()) {
String s=StdIn.readString();
if (s.equals("+")) {double right=vals.pop();
double left=vals.pop();v=left+right; vals.push(v);}
else if (s.equals("-")) {double right=vals.pop();
double left=vals.pop();v=left-right; vals.push(v);}
else if (s.equals("*")) {double right=vals.pop();
double left=vals.pop();v=left*right; vals.push(v);}
else if (s.equals("/")) {double right=vals.pop();
double left=vals.pop();v=left/right; vals.push(v);}
else vals.push(Double.parseDouble(s));
}
StdOut.println(vals.pop());
}
每次彈出兩個時還要分別賦值真的很心累。之後深入學習後再來嘗試想想別的方法,還有關於中綴表示式與字尾表示式的轉化問題。不得不說E.W.Dijkstra的雙棧演算法真的很妙,值得反覆學習。