計算字符串表達式的值


一、題目描述

給你一個字符串,包含+,-,*,/和(),數字為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;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM