zoukankan      html  css  js  c++  java
  • Java描述表达式求值的两种解法:双栈结构和二叉树

    Java描述表达式求值的两种解法:双栈结构和二叉树

    原题大意:表达式求值

    求一个非负整数四则混合运算且含嵌套括号表达式的值。如:

    # 输入:
    1+2*(6/2)-4
    # 输出:
    3.0
    

    数据保证:

    1. 保证表达式合法(含除数不为0)。
    2. 保证运算数是非负整数。

    双栈版

    维护两个栈: 符号栈,数字栈,遍历输入串过程中计算

    1. 数字直接入栈
    2. 符号入栈
      a. 符号栈为空
      b. 当前符号优先于栈顶符号
      c. 栈顶为'('
    3. 符号出栈计算: 栈顶符号非'(' 且 优先级更高.
    class ExpStack {
        private static final String LEVEL_OPTS = ")+-*/(";
    
        public double solve(String input) {
            Stack<Character> optStack = new Stack<>();
            Stack<Double> numStack = new Stack<>();
            int i = 0;
            while (i < input.length()) {
                if (Character.isDigit(input.charAt(i))) { // 如果是数字直接入栈
                    int t = 0;
                    for (; i < input.length() && Character.isDigit(input.charAt(i)); i++) {
                        t = t * 10 + input.charAt(i) - '0';
                    }
                    numStack.push((double) t);
                } else {// 如果是操作符
                    //栈为空 或 当前优先于栈顶: 入栈
                    if (optStack.isEmpty() || compPriority(input.charAt(i), optStack.peek()) > 0) {
                        optStack.push(input.charAt(i++));
                    } else if (optStack.peek() == '(') { // 栈顶为左括号 '('
                        if (input.charAt(i) == ')') { // 括号完成: 弹出'('
                            optStack.pop();
                        } else { // 括号开始 : 入栈
                            optStack.push(input.charAt(i));
                        }
                        i++;
                    } else { // 栈顶优先级更高且非 '(' : 运算
                        double top = numStack.pop();
                        numStack.push(calc(numStack.pop(), optStack.pop(), top));
                    }
                }
            }
            while (!optStack.isEmpty()) {
                double top = numStack.pop();
                numStack.push(calc(numStack.pop(), optStack.pop(), top));
            }
            return numStack.pop();
        }
    
        private int compPriority(char c1, char c2) {
            return LEVEL_OPTS.indexOf(c1) - LEVEL_OPTS.indexOf(c2);
        }
    
        private double calc(double x, char o, double y) {
            switch (o) {
                case '+':
                    return x + y;
                case '-':
                    return x - y;
                case '*':
                    return x * y;
                case '/':
                    return x / y;
            }
            return 0;
        }
    }
    

    二叉树版

    构建二叉树: 非叶子节点为符号,叶子节点为数字. 最终后序搜索计算
    二分点: 表达式中最后一个计算的运算符

    1. 排除括号后
    2. 优先取 + | -
    3. 再考虑 * | /
    class ExpTree {
        private String mInput;
        private java.util.LinkedList<Node> mTree;
    
        public double solve(String input) {
            mInput = input;
            mTree = new java.util.LinkedList<>();
    
            buildTree(0, mInput.length());
    
            return dfs(mTree.size() - 1);
        }
    
    
        private int buildTree(int li, int ri) {
    
            try { // 先尝试吧表达式解析为叶子节点(纯运算数)
                int n = Integer.parseInt(mInput.substring(li, ri));
                Node node = new Node(n, -1, -1);
                mTree.addLast(node);
                return mTree.size() - 1;
            } catch (Exception ignore) {
            }
    
            // 找到最外层的运算符(最后一个计算的运算符,优先级最低的符号)
            int opt, as = -1, md = -1, bracket = 0;
            for (int i = li; i < ri; i++) {
                switch (mInput.charAt(i)) {
                    case '(':
                        bracket++;
                        break;
                    case ')':
                        bracket--;
                        break;
                    case '+':
                    case '-':
                        if (bracket == 0) {
                            as = i;
                        }
                        break;
                    case '*':
                    case '/':
                        if (bracket == 0) {
                            md = i;
                        }
                        break;
                }
            }
            opt = as < 0 ? md : as;
            if (opt < 0) { // 发现这是一个被括号包裹的表达式(去掉括号重新构造)
                return buildTree(li + 1, ri - 1);
            }
            // 依次构造左右子树
            Node node = new Node(mInput.charAt(opt), buildTree(li, opt), buildTree(opt + 1, ri));
            mTree.addLast(node);
            return mTree.size() - 1;
        }
    
        private double dfs(int i) { // 后序遍历求解
            if (mTree.get(i).lch == -1 && mTree.get(i).rch == -1) {
                return mTree.get(i).num;
            }
            switch (mTree.get(i).opt) {
                case '+':
                    return dfs(mTree.get(i).lch) + dfs(mTree.get(i).rch);
                case '-':
                    return dfs(mTree.get(i).lch) - dfs(mTree.get(i).rch);
                case '*':
                    return dfs(mTree.get(i).lch) * dfs(mTree.get(i).rch);
                case '/':
                    return dfs(mTree.get(i).lch) / dfs(mTree.get(i).rch);
            }
            return 0;
        }
    
        private static class Node {
            double num;
            char opt;
            int lch, rch;
    
            Node(double n, int l, int r) {
                num = n;
                initChild(l, r);
            }
    
            Node(char o, int l, int r) {
                opt = o;
                initChild(l, r);
            }
    
            private void initChild(int l, int r) {
                lch = l;
                rch = r;
            }
        }
    }
    

    测试驱动函数

    public class Main {
        public static void main(String[] args) {
            Scanner cin = new Scanner(System.in);
            String input = cin.nextLine();
    
            double t = new ExpTree().solve(input);
            T.d(t);
            double s = new ExpStack().solve(input);
            T.d(s);
        }
    }
    
  • 相关阅读:
    &【12】Python 函数
    &【11】Python 流程控制
    &【09】Python 数据类型之dictionary
    &【07】Python 数据类型之元组
    &【08】Python 数据类型之set
    &【06】Python 数据类型之list
    &【05】Python 彻底搞懂分片操作
    &【04】Python 数据结构之序列
    SpringBoot-HelloWorld(三)
    SpringBoot-了解微服务(二)
  • 原文地址:https://www.cnblogs.com/chavin/p/11217036.html
Copyright © 2011-2022 走看看