大家都知道四則運算表達式是有優(yōu)先條件的 。比如先乘除再加減。而且如果有括號的話還要先計算括號里面。有沒有想過現(xiàn)在的高級計算器是如何實現(xiàn)這一功能的呢?
這里面的困難就在于乘除有時候在后面卻要先計算,在加上有括號的情況就更加復雜了。
- 后綴表達式
類似 9 + (3 - 1) * 3 + 10 / 2 是我們常見的表達式,叫『中綴表達式』。后綴表達式不同與中綴表達式,之所以叫“后綴表達式”是因為所有的運算符都在數(shù)字后面出現(xiàn)。所以9 + (3 - 1) * 3 + 10 / 2的后綴表達式為:9 3 1 - 3 * + 10 2 / +
顯然,是沒有括號的。
- 后綴表達式計算結(jié)果
后綴表達式為:9 3 1 - 3 * + 10 2 / +
規(guī)則:從左到右遍歷遍歷表達式的每一個數(shù)字和符號,遇到數(shù)字就進棧 ,遇到符號就棧頂?shù)膬蓚€數(shù)字出棧,然后進行運算,然后將運算結(jié)果進棧 。一直到最后,棧里面的值即為最終結(jié)果。
- 初始化空棧, 9 3 1 依次進棧。棧內(nèi)從下到上依次是:9,3,1
- 然后 - 號進棧,3 - 1 = 2, 2 進棧。棧內(nèi)從下到上依次是:9,2
- 接著 3 進棧。棧內(nèi)從下到上依次是:9,2,3
- * 號進棧,2 * 3 = 6,6 進棧。棧內(nèi)從下到上依次是:9,6
- + 號進棧,9 + 6 = 15, 15 進棧。棧內(nèi)從下到上依次是: 15
- 10, 2 依次進棧。棧內(nèi)從下到上依次是: 15,10,2
- / 號進棧,10 / 2 = 5, 5 進棧。棧內(nèi)從下到上依次是: 15,5
- + 號進棧,15 + 5 = 20。20 進棧。
至此結(jié)束,表達式最終結(jié)果:20
看來計算機果然適合計算后綴表達式求值,那么現(xiàn)在的問題就是如何把我們常見的中綴表達式轉(zhuǎn)換為后綴表達式呢?
- 中綴表達式轉(zhuǎn)后綴表達式
規(guī)則:從左到右遍歷表達式的每個數(shù)字和符號
- 遇到數(shù)字直接輸出,成為后綴表達式的一部分。
- 棧為空時,遇到運算符,直接入棧
- 當前符號是 (, 則直接進棧
- 當前符號是 ), 則把棧中的符號依次出棧,直到遇到 )為止。) 不輸出。
- 若是 + - * / 運算符號,彈出所有優(yōu)先級大于或者等于該運算符的棧頂元素,然后將該運算符入棧;直到遇到棧頂符號為 ) 或棧空 [+ - 為一級,* / 為 二級]
中綴表達式 9 + (3 - 1) * 3 + 10 / 2 轉(zhuǎn)后綴表達式為: 9 3 1 - 3 * + 10 2 / +
- 9 直接輸出。結(jié)果集:9;
- + 入棧。結(jié)果集:9;棧內(nèi)從下到上依次是:+
- ( 直接入棧。結(jié)果集:9;棧內(nèi)從下到上依次是:+,(
- 3 直接輸出。結(jié)果集:9,3;棧內(nèi)從下到上依次是:+,(
- - 入棧,優(yōu)先級低于棧頂符號 (,直接入棧。結(jié)果集:9,3;棧內(nèi)從下到上依次是:+,(,-
- 1 直接輸出。結(jié)果集:9,3,1;棧內(nèi)從下到上依次是:+,(,-
- 下一個符號是 ),因此循環(huán)出棧,直到遇到 (.結(jié)果集:9,3,1,-;棧內(nèi)從下到上依次是:+
- * 入棧。因為棧頂是 +,優(yōu)先級低于 *, 所以 * 直接入棧。結(jié)果集:9,3,1,-;棧內(nèi)從下到上依次是:+,*
- 3 直接輸出。結(jié)果集:9,3,1,-,3;棧內(nèi)從下到上依次是:+,*
- + 入棧,棧頂 * 優(yōu)先級高于 +,固 * 出棧并輸出。下一個是 +, 優(yōu)先級等于 +。出棧,+ 入棧。結(jié)果集:9,3,1,-,3,*,+;棧內(nèi)從下到上依次是:+
此時棧底的+是3+10的+,表達式里面的+是第一個+ - 10 直接輸出。結(jié)果集:9,3,1,-,3,*,+,10;棧內(nèi)從下到上依次是:+
- / 入棧,優(yōu)先級高于棧頂符號 +。直接入棧。結(jié)果集:9,3,1,-,3,*,+,10;棧內(nèi)從下到上依次是:+,/
- 2 直接輸出。結(jié)果集:9,3,1,-,3,*,+,10,2;棧內(nèi)從下到上依次是:+,/
- 循環(huán)出棧。結(jié)果集:9,3,1,-,3,*,+,10,2,/,+
代碼如下:
/**
* 根據(jù)后綴表達式計算結(jié)果集
* @param result
* @return
*/
private double getResult(List<String> result) {
if (null == result || result.size() == 0) {
throw new RuntimeException("表達式不合法!");
}
Stack<String> stack = new Stack<>();
Set<String> operation = new HashSet<>(Arrays.asList("+", "-", "*", "/"));
double d = 0.0d;
for (String str : result) {
if (!operation.contains(str)) {
stack.push(str);
} else {
double up = Double.parseDouble(stack.pop());
double down = Double.parseDouble(stack.pop());
switch (str) {
case "+":
d = down + up;
break;
case "-":
d = down - up;
break;
case "*":
d = down * up;
break;
case "/":
d = down / up;
break;
default:
break;
}
stack.push(String.valueOf(d));
}
}
return Double.parseDouble(stack.pop());
}
/**
* 將中綴表達式轉(zhuǎn)換為后綴表達式
*
* @param operationExpression
* @return
*/
private List<String> operationExpressionToRPN(String operationExpression) {
if (null == operationExpression || "".equals(operationExpression)) {
throw new RuntimeException("表達式不合法!");
}
List<String> result = new LinkedList<>();
char[] chars = operationExpression.toCharArray();
Set<String> operation = new HashSet<>(Arrays.asList("+", "-", "*", "/"));
Set<String> numbers = new HashSet<>(Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
Stack<String> stack = new Stack<>();
StringBuffer sb = new StringBuffer();
String lastChar = "";
for (char c : chars) {
String currentChar = String.valueOf(c);
// 上一個字符 和 當前字符 都是數(shù)字的話
if (numbers.contains(lastChar) && numbers.contains(currentChar)) {
String lastestChar = result.get(result.size() - 1);
result.remove(result.size() - 1);
result.add(lastestChar + currentChar);
lastChar = currentChar;
continue;
}
if (numbers.contains(currentChar)) {
sb.append(currentChar);
} else {
/**
*
* 1:當前符號是 (, 則直接進棧
* 2:當前符號是 + - * /, 彈出所有優(yōu)先級大于或者等于該運算符的棧頂元素,然后將該運算符入棧
* 3:當前符號是 ), 則把棧中的符號依次出棧,直到遇到 )為止。
*/
if ("(".equals(currentChar)) {
stack.push(currentChar);
} else if (operation.contains(currentChar)) {
/*while (true) {
// 棧空、棧頂符號為"("、當前符號優(yōu)先級 > 棧頂符號優(yōu)先級。當前符號入棧
if (stack.isEmpty() || getOperationLevel(stack.peek()) < getOperationLevel(currentChar) || "(".equals(stack.peek())) {
stack.push(currentChar);
break;
} else {
result.add(stack.pop());
}
}*/
while(!stack.isEmpty() && (getOperationLevel(stack.peek()) >= getOperationLevel(currentChar)) && !"(".equals(stack.peek())){
result.add(stack.pop());
}
stack.push(currentChar);
} else if (")".equals(currentChar)) {
String str;
while (!stack.isEmpty() && !"(".equals(str = stack.pop())) {
result.add(str);
}
}
}
if (!"".equals(sb.toString())) {
result.add(sb.toString());
sb.delete(0, sb.length());
}
lastChar = currentChar;
}
// 最后清空棧
while (!stack.isEmpty()) {
result.add(stack.pop());
}
return result;
}
private int getOperationLevel(String operation) {
int result;
switch (operation) {
case "+":
result = 1;
break;
case "-":
result = 1;
break;
case "*":
result = 2;
break;
case "/":
result = 2;
break;
default:
result = 0;
break;
}
return result;
}