一、題目描述
給你一個字符串,包含+,-,*,/和(),數字為0-9,讓計算該表達式的值,例如"1+2*3-(8/4)+6",結果為11,這是前幾天面試去哪兒網,二面面試官讓手撕的題目。記憶中本科的時候遇到過,當時也沒啥思路。其實這個題需要分兩步完成,第一步:把字符串表達式的中綴形式轉為后綴形式,怎么轉有一定的規則。第二步:計算后綴表達式的值。
關於什么是前綴,中綴,后綴表達式,請讀者自己查閱資源,這里就不介紹了。我們只談如何從中綴轉為后綴,規則如下:
首先定義一個棧stack用來保存操作符,定義一個List保存后綴表達式的結果,令字符串的當前字符為c:
1、如果c為操作數,從'0' - '9',則直接添加到list中
2、如果c為操作符,例如+,-,*,/,首先判斷棧是否為空,如果為空,則操作符入棧,如果不為空,當棧頂操作符的優先級比c的優先級高,或者相等的時候,把棧頂操作符彈出,並添加到list中,直到遇到左括號,或者棧頂元素的優先級比c低的時候停止。然后把操作符c入棧。
3、如果c為左括號,直接入棧
4、如果c為右括號,則依次彈出棧內的操作符並添加到list,直到遇到左括號。把左括號彈出,但是不添加到list。
5、當字符串中每個元素都遍歷完后,把棧中所有的操作符全部彈出並添加到list中
上面的操作完成后,后綴表達式也就全部保存到了list中,然后我們就可以計算后綴表達式的值了。計算步驟如下:
先定義一個棧stack,用來保存操作數,以及中間結果,當遍歷list的時候,如果當前元素為:
1、如果為操作數,則直接入棧
2、如果為操作符,則從棧中依次彈出2個元素b和a,然后根據操作符的不同,計算a xxx b的值,把計算結果壓棧
3、當list遍歷完后,棧中肯定只剩下一個元素,就是最終的結果。
二、代碼演示
import java.util.LinkedList; import java.util.List; import java.util.Scanner; import java.util.Stack; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.nextLine(); sc.close(); System.out.println(getResult(getPost(s))); } /** * 計算后綴表達式的值 * @param list 后綴表達式 * @return */ public static int getResult(List<Character> list) { Stack<String> stack = new Stack<>(); for(int i = 0; i < list.size(); i++) { char c = list.get(i); if(c >= '0' && c <= '9') { //當遇到操作數直接壓棧 stack.push(c + ""); } else {//當遇到操作符的時候,從棧中彈出兩個元素,然后根據運算符的不同做相應的運算,然后把運算結果壓棧。 int b = Integer.parseInt(stack.pop()); int a = Integer.parseInt(stack.pop()); if(c == '+') stack.push(a + b + ""); else if(c == '-') stack.push(a - b + ""); else if(c == '*') stack.push(a * b + ""); else stack.push(a / b + ""); } } //最終棧中肯定只剩下一個元素,就是計算的結果。 return Integer.parseInt(stack.pop()); } /** * 把中綴表達式轉為后綴表達式 * 前提條件:操作數的范圍為0-9,操作符為+,-,*,/,以及() * @param s 字符串表達式 * @return */ public static List<Character> getPost(String s) { Stack<Character> stack = new Stack<>(); //保存操作符 LinkedList<Character> list = new LinkedList<>(); //保存最終的后綴表達式 for(int i = 0; i < s.length(); i++) { char c = s.charAt(i); if(c >= '0' && c <= '9') list.add(c); //操作數直接輸出到后綴表達式中 else if(c == '+' || c == '-' || c == '*' || c == '/') { //把比當前操作符c的優先級高或者等於c的優先級的操作符依次彈出棧並保存到后綴表達式中,直到遇到棧頂操作符的優先級比c低 while(!stack.isEmpty()) { if(compare(stack.peek()) >= compare(c)) { list.add(stack.pop()); } else break; } stack.push(c);//當前操作符c入棧 } else if(c == '(') stack.push(c); //左括號直接入棧 else { //當遇到右括號的時候,把棧中的操作符依次彈出並追加到后綴表達式中,直到遇到左括號停止,並把左括號彈出。 while(stack.peek() != '(') { list.add(stack.pop()); } stack.pop(); } } //把棧中所有的操作符全部彈出追加到后綴表達式中 while(!stack.isEmpty())list.add(stack.pop()); return list; } /** * 計算運算符的優先級 * @param c 運算符 * @return */ public static int compare(char c) { if(c == '+' || c == '-') return 1; else if(c == '*' || c == '/') return 2; else return 0; } }