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

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

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

中缀转后缀

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

import java.util.ArrayDeque;
import java.util.Deque;

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()=='*')){
                        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();
    }
}

c++完整代码

int main() {
    string target="1+2*3";
    stack<char>s;
    string ans;
    for(auto iter=target.begin();iter!=target.end();iter++){
        char c=*iter;
        switch(c){
            case '(':
                s.push('(');
                break;
            case ')':
                while(!s.empty() && s.top()!='('){
                    char cc=s.top();s.pop();
                    ans+=cc;
                }
                s.pop();
                break;
            case '+':
            case '-':
                while(s.empty()==false && s.top()!='('){
                    char cc=s.top();s.pop();
                    ans+=cc;
                }
                s.push(c);
                break;
            case '*':
            case '/':
                while (s.empty()==false && (s.top()=='*'||s.top()=='/')){
                    char cc=s.top();s.pop();
                    ans+=cc;
                }
                s.push(c);
                break;
            default:
                ans+=c;
        }
    }
    while (!s.empty()){
        char cc=s.top();s.pop();
        ans+=cc;
    }
    stack<int>t;
    for(auto iter=ans.begin();iter!=ans.end();iter++){
        char c=*iter;
        if(isdigit(c)){
            t.push(c-'0');
        }else{
            int x=t.top();t.pop();
            int y=t.top();t.pop();
            switch(c){
                case '+':
                    t.push(y+x);
                    break;
                case '-':
                    t.push(y-x);
                    break;
                case '/':
                    t.push(y/x);
                    break;
                case '*':
                    t.push(y*x);
                    break;
            }
        }
    }
    cout<<t.top();
}

将中缀表达式转成抽象语法树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();
    }


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值