java 计算器逻辑

public class Calculate {

    public static void main(String[] args) {

        Stack<Symbol> ops = new Stack<>();
        Stack<Double> vals = new Stack<>();
        while (!StdIn.isEmpty()) {
            String s = StdIn.readString();
            if (s.equals("e")) {
                break;
            }
            if (s.trim().equals(" ")) {
                continue;
            }
            Operation o = Operation.fromSymbol(s);
            if (o != null) {
                ops.push(o);
                continue;
            }

            Bound b = Bound.fromSymbol(s);
            if (b != null) {
                b.execute(ops, vals);
                continue;
            }

            vals.push(Double.parseDouble(s));

        }
        System.out.println(vals.pop());

    }

}

interface Symbol {

}

/**
 * 边界符号,遇到之后做点什么
 *
 * @author yaoqiang
 */
enum Bound implements Symbol {
    PREFIX("(") {
        @Override
        public void execute(Stack<Symbol> ops, Stack<Double> vals) {
            ops.add(this);
        }

    },
    SUFFIX(")") {
        @Override
        public void execute(Stack<Symbol> ops, Stack<Double> vals) {
            List<Symbol> list = new ArrayList<>();
            Symbol s = ops.pop();
            do {
                list.add(s);
                s = ops.pop();
            } while (s != Bound.PREFIX);

            List<Double> val = new ArrayList<>();

            for (int i = 0; i <= list.size(); i++) {
                val.add(vals.pop());
            }

            Symbol[] arr = list.toArray(new Symbol[list.size()]);
            Integer[] indexArr = new Integer[list.size()];

            for (int i = 0; i < list.size(); i++) {
                indexArr[i] = i;
            }
            for (int i = 1; i < list.size(); i++) {
                Symbol temp = arr[i];

                int sj = i;
                // 数值越低,则优先级越高
                // 这里需要注意一个问题,插入排序是稳定的,而这里 需要与稳定相反
                // 由于取出是按照栈顺序的 所以原始索引 是左边的索引大于右边的索引
                // 优先级越高,则数值越低,这样的 操作符 和 索引位置应该被推到前面。 虽然只操作索引,不过操作符也得同步,才能够进行后续的比较。
                // 注意:核心问题,相等的操作符。如果操作符相同,则应该是 左边的优先级更高,而左边的索引更大。
                // 所以 逻辑就变得有些混乱,即 按照 order 从低到高排序。
                // 如果相等 ( 从 栈取出,索引顺序为 从 右到左 ),则应该 让索引更大的排前面。即 即使相同,也要交换,让大索引优先。这与稳定刚好相反
                for (int j = i; j > 0 && ((Operation) arr[j - 1]).getOrder() >= ((Operation) temp).getOrder(); j--) {
                    arr[j] = arr [j-1];
                    indexArr[j] = indexArr[j - 1];
                    sj = j - 1;
                }

                if (sj != i) {
                    indexArr[sj] = i;
                    arr[sj] = temp;
                }
            }

            //  ( 1 + 2 * 3 + (  2 + 3 * 4 )  ) e
            //  当 优先级高的被合并的时候,不得不 合并结果到val中,比如 2 , 3 合并为 2,所以原来的索引 i ,i + 1 也就失效
            //  虽然失效,不过依然又规律可循,记录操作索引,如果 运行过的索引 存在 比 当前索引更小的,则需要减去这些数量(栈,从后到前,越左的索引,越大)
            //  得到的即 合并后的索引数量。
            //  list  存储的是 操作符的原始位置,由于操作符没有做任何合并,所以索引不需要改变,依然按照原来的索引搜索。
            Set<Integer> set = new HashSet<>();
            for (Integer idx : indexArr) {
                Integer finalIdx = idx;
                idx = idx - Long.valueOf(set.stream().filter(i->i< finalIdx).count()).intValue();
                Double d = ((Operation) list.get(finalIdx)).execute(val.get(idx + 1), val.get(idx));
                set.add(idx);
                val.remove(idx.intValue());
                val.remove(idx.intValue());
                val.add(idx, d);
            }

            vals.push(val.get(0));
        }

    };

    private final String symbol;

    private static final EnumSet<Bound> all;

    static {
        all = EnumSet.allOf(Bound.class);
    }

    public static Bound fromSymbol(String s) {
        return all.stream().filter(o -> o.symbol.equals(s)).findFirst().orElse(null);
    }

    Bound(String symbol) {
        this.symbol = symbol;
    }

    public abstract void execute(Stack<Symbol> ops, Stack<Double> vals);

}

/**
 * 操作符
 *
 * @author root
 */
enum Operation implements Symbol {

    PLUS("+", 1) {
        @Override
        public double execute(double one, double two) {
            return one + two;
        }
    },
    MINUS("-", 1) {
        @Override
        public double execute(double one, double two) {
            return one - two;
        }
    },
    MULTIPLY("*", 0) {
        @Override
        public double execute(double one, double two) {
            return one * two;
        }
    },
    DIVIDE("/", 0) {
        @Override
        public double execute(double one, double two) {
            return one / two;
        }
    };

    private final String symbol;

    private final Integer order;

    private static final EnumSet<Operation> all;

    static {
        all = EnumSet.allOf(Operation.class);
    }

    public static Operation fromSymbol(String s) {
        return all.stream().filter(o -> o.symbol.equals(s)).findFirst().orElse(null);
    }

    Operation(String symbol, Integer order) {
        this.symbol = symbol;
        this.order = order;
    }

    public Integer getOrder() {
        return this.order;
    }

    public abstract double execute(double one, double two);
}

        <dependency>
            <groupId>edu.princeton.cs</groupId>
            <artifactId>algs4</artifactId>
            <version>1.0.3</version>
        </dependency>

示例输入:( 1 + 2 * 3 + ( 2 + 3 * 4 ) ) e

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值