在做一道算法題時遇到該問題,寫一個計算器其中有加減乘除和括號,用最快的算法算出來。後來根據答案想了下用下面的算法是複合答案的意思。
定義:
- 中綴表達式:
我們平時寫的數學表達式一般爲中綴表達式,如“5+2*(3*(3-1*2+1))”,直接拿中綴表達式直接讓計算機計算表達式的結果並不能做到。
- 後綴表達式:
把中綴表達表達式“5+2*(3*(3-1*2+1))”轉化“523312*-1+**+”這樣的形式,就是後綴表達式。這種記法叫做後綴(postfix)或逆波蘭(reverse Polish)記法。計算這個問題最容易的方法就是使用一個棧。
轉換方法:
- 按次序讀取中綴表達式的字符。
- 讀到一個操作數的時候,立即放入到輸出中。
- 讀到操作符“+”,“-”,“*”,“/”,則從棧中彈出棧元素並輸出,直到遇到優先級更低或者“(”的爲止操作符爲止(該元素不出棧)。
- 讀到操作符“(”,則直接把“(”壓入棧中。
- 讀到操作符“)”,則從棧中彈出棧元素並輸出,直到遇到第一個“(”爲止。其中“(”不再添加到輸出中,而是直接捨棄。
- 當輸入爲空時,把棧裏的操作符全部依次彈出並輸出。
舉例:
操作 | 說明 | 棧 | 輸出 |
讀取5 | 把操作數直接輸出 | 5 | |
讀取+ | 棧爲空,把操作符壓入棧 | + | 5 |
讀取2 | 把操作數直接輸出 | + | 52 |
讀取* | 棧頂元素爲+,優先級低於*,把操作符壓入棧 | +* | 52 |
讀取( | 把 ( 直接壓入棧 | +*( | 52 |
讀取3 | 把操作數直接輸出 | +*( | 523 |
讀取* | 棧頂元素爲(,把操作符壓入棧 | +*(* | 523 |
讀取( | 把 ( 直接壓入棧 | +*(*( | 523 |
讀取3 | 把操作數直接輸出 | +*(*( | 5233 |
讀取- | 棧頂元素爲(,把操作符壓入棧 | +*(*(- | 5233 |
讀取1 | 把操作數直接輸出 | +*(*(- | 52331 |
讀取* | 棧頂元素爲-,優先級低於*,把操作符壓入棧 | +*(*(-* | 52331 |
讀取2 | 把操作數直接輸出 | +*(*(-* | 523312 |
讀取+ | 棧頂元素爲*,優先級高於+,以此彈出*,-到輸出,到 ( 停止,把操作符壓入棧中 | +*(*(+ | 523312*- |
讀取1 | 把操作數直接輸出 | +*(*(+ | 523312*-1 |
讀取) | 從棧中彈出+到輸出,遇到第一個 ( 停止,把 ( 彈出棧 | +*(* | 523312*-1+ |
讀取) | 從棧中彈出*到輸出,遇到第一個 ( 停止,把 ( 彈出棧 | +* | 523312*-1+* |
結束讀取 | 把棧中的元素全部彈出到輸出 | 523312*-1+**+ |
後綴表達式的計算:
- 按次序讀取後綴表達式的每一個字符。
- 讀取到操作數時,把操作數壓入棧中。
- 讀取到操作符時,對棧頂的2個操作數做相應運算,要注意操作數的前後順序。結果壓入棧中。
- 讀取完所有的字符後,彈出棧。得到的值就是所求結果。
代碼:
import java.util.Stack;
public class Main {
static Stack<Character> op = new Stack<>();
public static Float getv(char op, Float f1, Float f2){
if(op == '+') return f2 + f1;
else if(op == '-') return f2 - f1;
else if(op == '*') return f2 * f1;
else if(op == '/') return f2 / f1;
else return Float.valueOf(-0);
}
/**
* calculate the value of the reverse Polish expression
* @param rp - reverse Polish expression
* @return - result of the expression
*/
public static float calrp(String rp){
Stack<Float> v = new Stack<>();
char[] arr = rp.toCharArray();
int len = arr.length;
for(int i = 0; i < len; i++){
Character ch = arr[i];
// if is operand, push to the stack
if(ch >= '0' && ch <= '9') v.push(Float.valueOf(ch - '0'));
// if is operator, calculate the result
// with top 2 operands in the stack,
// push the result into the stack
else v.push(getv(ch, v.pop(), v.pop()));
}
return v.pop();
}
/**
* from infix to postfix
* @param s - String in the form of infix
* @return String in the form of postfix
*/
public static String getrp(String s){
char[] arr = s.toCharArray();
int len = arr.length;
String out = "";
for(int i = 0; i < len; i++){
char ch = arr[i];
if(ch == ' ') continue;
// if is operand, add to
// the output stream directly
if(ch >= '0' && ch <= '9') {
out+=ch;
continue;
}
//if is '(', push to the stack directly
if(ch == '(') op.push(ch);
//if is '+' or '-', pop the operator
// from the stack until '(' and add to
// the output stream
//push the operator to the stack
if(ch == '+' || ch == '-'){
while(!op.empty() && (op.peek() != '('))
out+=op.pop();
op.push(ch);
continue;
}
//if is '*' or '/', pop the operator stack and
// add to the output stream
// until lower priority or '('
//push the operator to the stack
if(ch == '*' || ch == '/'){
while(!op.empty() && (op.peek() == '*' || op.peek() == '/'))
out+=op.pop();
op.push(ch);
continue;
}
//if is ')' pop the operator stack and
// add to the output stream until '(',
// pop '('
if(ch == ')'){
while(!op.empty() && op.peek() != '(')
out += op.pop();
op.pop();
continue;
}
}
while(!op.empty()) out += op.pop();
return out;
}
public static void main(String[] args){
//constraint: the operand should be
// equal or greater than 0
// but equal or less than 9
String exp = "5+2*(3*(2-1))";
System.out.println(calrp(getrp(exp)));
}
}
輸出:
11.0
————————————————
版權聲明:本文爲CSDN博主「Ring_k」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ring_k/article/details/79598961