算法-计算机如何计算数学表达式

计算机如何计算数学表达式

平时写的1+2是中缀表达式,对应二叉树的中序遍历
计算机实际计算过程是:先将我们写的中缀表达式转成后缀表达式(二叉树的后序遍历),然后计算的。

中缀转后缀

下面是中缀转后缀的代码,用到了运算符优先级算法,
算法的基本思想:*/的优先级比±高,当前时运算符时,只要栈中的运算符的优先级>=当前运算符,则出栈
注意:表达式对应的语法树一定要画正确,否则可能导致对优先级算法的理解有误!

class Solution {
    
    
    /**
     * 中缀表达式转换为后缀表达式 "3*4-2*5" -> "34*25*-"
     * 后缀表达式也就是逆波兰表达式。
     */
    private String infixToPostfix(String s) {
    
    
        StringBuilder sb = new StringBuilder();
        Deque<Character> stack = new ArrayDeque<>();
        for (int i = 0; i < s.length(); i++) {
    
    
            char c = s.charAt(i);
            switch (c) {
    
    
                case '(':
                    stack.addLast(c);
                    break;
                case ')':
                    while (!stack.isEmpty()&&stack.peekLast()!='('){
    
    
                        sb.append(stack.removeLast());
                    }
                    stack.removeLast(); //(出栈
                    break;
                case '+':
                case '-':
                    while (!stack.isEmpty()&&stack.peekLast()!='('){
    
    
                        sb.append(stack.removeLast());
                    }
                    stack.addLast(c);
                    break;
                case '*':
                case '/':
                    while (!stack.isEmpty()&&stack.peekLast()!='('&&stack.peekLast()!='+'&&stack.peekLast()!='-'){
    
    
                        sb.append(stack.removeLast());
                    }
                    stack.addLast(c);
                    break;
                default:
                    sb.append(c);
            }
        }
        while (!stack.isEmpty()){
    
    
            sb.append(stack.removeLast());
        }
        return sb.toString();
    }
}

后缀表达式求值

添加链接描述
得到后缀表达式之后,就可以进行计算了,还是利用栈。

class Solution {
    
    
    public int evalRPN(String[] tokens) {
    
    
        Stack<Integer> stack=new Stack<>();
        for (String s : tokens) {
    
    
            if(s.length()>1 || Character.isDigit(s.charAt(0))){
    
     //数字
                stack.push( Integer.parseInt(s));
            }else {
    
    
                int num2 = stack.pop();
                int num1 = stack.pop();
                switch (s) {
    
    
                    case "+":
                        stack.push(num1 + num2);
                        break;
                    case "-":
                        stack.push(num1 - num2);
                        break;
                    case "*":
                        stack.push(num1 * num2);
                        break;
                    case "/":
                        stack.push(num1 / num2);
                        break;
                    default:
                }
            }
        }
        return stack.pop();
    }
}

将中缀表达式转成抽象语法树AST

上面是模拟计算机是如何计算的,实际计算机在计算过程中,是将表达式中的每个字符封装成语法树节点,然后组装成抽象语法树,最后遍历这颗语法树求值,下面简单写下封装的逻辑代码

class Solution {
    
    
    /**
     * 利用后缀表达式构造AST
     */
    public Node expTree(String s) {
    
    
       //中缀转后缀
       s=infixToPostfix(s);
       //封装
       Deque<Node>stack=new ArrayDeque<>();
        for (int i = 0; i < s.length(); i++) {
    
    
            char c=s.charAt(i);
            Node node = new Node(c);
            switch (c){
    
    
                case '+':
                case '-':
                case '*':
                case '/':
                    node.right=stack.removeLast();
                    node.left=stack.removeLast();
                    break;
                default:
            }
            stack.addLast(node);
        }
        return stack.pop();
    }


    /**
     * 中缀表达式转换为后缀表达式 "3*4-2*5" -> "34*25-"
     * 后缀表达式也就是逆波兰表达式。
     */
    private String infixToPostfix(String s) {
    
    
        StringBuilder sb = new StringBuilder();
        Deque<Character> stack = new ArrayDeque<>();
        for (int i = 0; i < s.length(); i++) {
    
    
            char c = s.charAt(i);
            switch (c) {
    
    
                case '(':
                    stack.addLast(c);
                    break;
                case ')':
                    while (!stack.isEmpty()&&stack.peekLast()!='('){
    
    
                        sb.append(stack.removeLast());
                    }
                    stack.removeLast(); //(出栈
                    break;
                case '+':
                case '-':
                    while (!stack.isEmpty()&&stack.peekLast()!='('){
    
    
                        sb.append(stack.removeLast());
                    }
                    stack.addLast(c);
                    break;
                case '*':
                case '/':
                    while (!stack.isEmpty()&&stack.peekLast()!='('&&stack.peekLast()!='+'&&stack.peekLast()!='-'){
    
    
                        sb.append(stack.removeLast());
                    }
                    stack.addLast(c);
                    break;
                default:
                    sb.append(c);
            }
        }
        while (!stack.isEmpty()){
    
    
            sb.append(stack.removeLast());
        }
        return sb.toString();
    }


}

猜你喜欢

转载自blog.csdn.net/qq_40337086/article/details/117111428