Java四则运算表达式求解

压栈思想计算Java运算表达式

栈的规则是先进后出。利用压栈的思想来计算四则运算表达式是这样的:我们给定两个栈,一个用来存放数字、一个用来存放对应的操作符。假定我们有一个给定的四则运算表达式a+b+c/d*(e+f)-d*a,那我们先把这个表达式拆分成一个个的数字或者是运算符、或者就是括号了。然后我们从左至右遍历每一个元素,遍历过程中遵循步骤和原则如下:

(1)遇到数字则直接压到数字栈顶。

(2)遇到运算符(+-*/)时,若操作符栈为空,则直接放到操作符栈顶,否则,见(3)。

(3)若操作符栈顶元素的优先级比当前运算符的优先级小,则直接压入栈顶,否则执行步骤(4)。

(4)弹出数字栈顶的两个数字并弹出操作符栈顶的运算符进行运算,把运算结果压入数字栈顶,重复(2)和(3)直到当前运算符被压入操作符栈顶。

(5)遇到左括号“(”时则直接压入操作符栈顶。

(6)遇到右括号“)”时则依次弹出操作符栈顶的运算符运算数字栈的最顶上两个数字,直到弹出的操作符为左括号。

下面的例子中分别使用java.util.Vector和java.util.Stack基于上述原则实现了这一运算过程。

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.regex.Pattern;  

public class Test {  

    public static void main(String args[]) {
        String computeExpr = "1 + 5 * 6 + 3 * (2 + 3*2+2-1+3*3) + 10/5 - 6*1";
        Test test = new Test();
        double result1 = test.computeWithVector(computeExpr);
        double result2 = test.computeWithStack(computeExpr);
        System.out.println(result1 + "=======" + result2);
    }  

    /**
     * 利用java.util.Vector计算四则运算字符串表达式的值,如果抛出异常,则说明表达式有误,这里就没有控制
     * @param computeExpr 四则运算字符串表达式
     * @return 计算结果
     */
    public double computeWithVector(String computeExpr) {
        StringTokenizer tokenizer = new StringTokenizer(computeExpr, "+-*/()", true);
        Vector<Double> nums = new Vector<Double>();
        Vector<Operator> operators = new Vector<Operator>();
        Map<String, Operator> computeOper = this.getComputeOper();
        Operator curOper;
        String currentEle;
        while (tokenizer.hasMoreTokens()) {
            currentEle = tokenizer.nextToken().trim();
            if (!"".equals(currentEle)) {//只处理非空字符
                if (this.isNum(currentEle)) { // 数字
                    nums.add(Double.valueOf(currentEle));
                } else { // 非数字,即括号或者操作符
                    curOper = computeOper.get(currentEle);
                    if (curOper != null) { // 是运算符
                        // 运算列表不为空且之前的运算符优先级较高则先计算之前的优先级
                        while (!operators.isEmpty()
                                && operators.lastElement().priority() >= curOper
                                        .priority()) {
                            compute(nums, operators);
                        }
                        // 把当前运算符放在运算符队列的末端
                        operators.add(curOper);
                    } else { // 括号
                        if ("(".equals(currentEle)) { // 左括号时直接放入操作列表中
                            operators.add(Operator.BRACKETS);
                        } else {// 当是右括号的时候就把括号里面的内容执行了。
                            // 循环执行括号里面的内容直到遇到左括号为止。试想这种情况(2+5*2)
                            while (!operators.lastElement().equals(Operator.BRACKETS)) {
                                compute(nums, operators);
                            }
                            //移除左括号
                            operators.remove(operators.size()-1);
                        }
                    }
                }
            }
        }
        // 经过上面代码的遍历后最后的应该是nums里面剩两个数或三个数,operators里面剩一个或两个运算操作符
        while (!operators.isEmpty()) {
            compute(nums, operators);
        }
        return nums.firstElement();
    }  

    /**
     * 利用java.util.Stack计算四则运算字符串表达式的值,如果抛出异常,则说明表达式有误,这里就没有控制
     * java.util.Stack其实也是继承自java.util.Vector的。
     * @param computeExpr 四则运算字符串表达式
     * @return 计算结果
     */
    public double computeWithStack(String computeExpr) {
        //把表达式用运算符、括号分割成一段一段的,并且分割后的结果包含分隔符
        StringTokenizer tokenizer = new StringTokenizer(computeExpr, "+-*/()", true);
        Stack<Double> numStack = new Stack<Double>();   //用来存放数字的栈
        Stack<Operator> operStack = new Stack<Operator>();  //存放操作符的栈
        Map<String, Operator> computeOper = this.getComputeOper();    //获取运算操作符
        String currentEle;  //当前元素
        while (tokenizer.hasMoreTokens()) {
            currentEle = tokenizer.nextToken().trim();  //去掉前后的空格
            if (!"".equals(currentEle)) {   //只处理非空字符
                if (this.isNum(currentEle)) { //为数字时则加入到数字栈中
                    numStack.push(Double.valueOf(currentEle));
                } else { //操作符
                    Operator currentOper = computeOper.get(currentEle);//获取当前运算操作符
                    if (currentOper != null) {  //不为空时则为运算操作符
                        while (!operStack.empty() && operStack.peek().priority() >= currentOper.priority()) {
                            compute(numStack, operStack);
                        }
                        //计算完后把当前操作符加入到操作栈中
                        operStack.push(currentOper);
                    } else {//括号
                        if ("(".equals(currentEle)) { //左括号时加入括号操作符到栈顶
                            operStack.push(Operator.BRACKETS);
                        } else { //右括号时, 把左括号跟右括号之间剩余的运算符都执行了。
                            while (!operStack.peek().equals(Operator.BRACKETS)) {
                                compute(numStack, operStack);
                            }
                            operStack.pop();//移除栈顶的左括号
                        }
                    }
                }
            }
        }
        // 经过上面代码的遍历后最后的应该是nums里面剩两个数或三个数,operators里面剩一个或两个运算操作符
        while (!operStack.empty()) {
            compute(numStack, operStack);
        }
        return numStack.pop();
    }  

    /**
     * 判断一个字符串是否是数字类型
     * @param str
     * @return
     */
    private boolean isNum(String str) {
        String numRegex = "^\\d+(\\.\\d+)?$";   //数字的正则表达式
        return Pattern.matches(numRegex, str);
    }  

    /**
     * 获取运算操作符
     * @return
     */
    private Map<String, Operator> getComputeOper() {
        return new HashMap<String, Operator>() { // 运算符
            private static final long serialVersionUID = 7706718608122369958L;
            {
                put("+", Operator.PLUS);
                put("-", Operator.MINUS);
                put("*", Operator.MULTIPLY);
                put("/", Operator.DIVIDE);
            }
        };
    }  

    /**
     * 取nums的最后两个数字,operators的最后一个运算符进行运算,然后把运算结果再放到nums列表的末端
     * @param nums
     * @param operators
     */
    private void compute(Vector<Double> nums, Vector<Operator> operators) {
        Double num2 = nums.remove(nums.size() - 1); // 第二个数字,当前队列的最后一个数字
        Double num1 = nums.remove(nums.size() - 1); // 第一个数字,当前队列的最后一个数字
        Double computeResult = operators.remove(operators.size() - 1).compute(
                num1, num2); // 取最后一个运算符进行计算
        nums.add(computeResult); // 把计算结果重新放到队列的末端
    }  

    /**
     * 取numStack的最顶上两个数字,operStack的最顶上一个运算符进行运算,然后把运算结果再放到numStack的最顶端
     * @param numStack  数字栈
     * @param operStack 操作栈
     */
    private void compute(Stack<Double> numStack, Stack<Operator> operStack) {
        Double num2 = numStack.pop(); // 弹出数字栈最顶上的数字作为运算的第二个数字
        Double num1 = numStack.pop(); // 弹出数字栈最顶上的数字作为运算的第一个数字
        Double computeResult = operStack.pop().compute(
                num1, num2); // 弹出操作栈最顶上的运算符进行计算
        numStack.push(computeResult); // 把计算结果重新放到队列的末端
    }  

    /**
     * 运算符
     */
    private enum Operator {
        /**
         * 加
         */
        PLUS {
            @Override
            public int priority() {
                return 1;
            }  

            @Override
            public double compute(double num1, double num2) {
                return num1 + num2;
            }
        },
        /**
         * 减
         */
        MINUS {
            @Override
            public int priority() {
                return 1;
            }  

            @Override
            public double compute(double num1, double num2) {
                return num1 - num2;
            }
        },
        /**
         * 乘
         */
        MULTIPLY {
            @Override
            public int priority() {
                return 2;
            }  

            @Override
            public double compute(double num1, double num2) {
                return num1 * num2;
            }
        },
        /**
         * 除
         */
        DIVIDE {
            @Override
            public int priority() {
                return 2;
            }  

            @Override
            public double compute(double num1, double num2) {
                return num1 / num2;
            }
        },
        /**
         * 括号
         */
        BRACKETS {
            @Override
            public int priority() {
                return 0;
            }  

            @Override
            public double compute(double num1, double num2) {
                return 0;
            }
        };
        /**
         * 对应的优先级
         * @return
         */
        public abstract int priority();  

        /**
         * 计算两个数对应的运算结果
         * @param num1  第一个运算数
         * @param num2  第二个运算数
         * @return
         */
        public abstract double compute(double num1, double num2);
    }
}  

Java四则运算表达式求解

时间: 2024-08-10 04:15:40

Java四则运算表达式求解的相关文章

计算四则运算表达式(Java语言实现)

计算四则运算表达式主要是分两步运算  第一步是把 中缀表达式 转换成 后缀表达式.参考大一下期学的 <数据结构与算法分析--C语言描述>3.3.3 教材,完成下列代码: static String mid_to_suf(String str){ Stack<Character> s = new Stack<Character>(); String suf = new String(); HashMap<Character, Integer> map = ne

四则运算表达式求值の各种心碎

实验三---四则运算表达式求值 一.基本要求: ( 1 ) 利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值. ( 2) 输入输出格式: 输入格式:在字符界面上输入一个中缀表达式,回车表示结束. 请输入表达式: 输入一个中缀表达式 输出格式:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后 缀表达式中两相邻操作数之间利用空格隔开:如果不正确,在字符界面上输出表达式错误提示. 逆波兰表达式为: 输出逆波兰表达式 运算结果为:输出运算后的结果 测试数据

四则运算表达式网页版

在网页上面生成一个四则运算表达式,用户可以输入表达式的值,然后系统提示结果是否正确.这个网页程序比本机程序来说容易一点,一是因为表达式中运算符的个数不超过三个,表达式容易获得.还有就是javascript自带了一个计算表达式的值的函数,我们可以调用这个函数来完成对表达式值的计算. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% Str

四则运算表达式生成器(C语言)

结对项目:四则运算表达式生成器(C语言) GitHub:https://github.com/peter-ye-code/Question-Builder 合作者:叶学涛(3118005024) 温德华(3118005021) 一.需求 四则运算表达式生成器的全部功能: 使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n 10 将生成10个题目. 使用 -r 参数控制题目中数值(自然数.真分数和真分数分母)的范围,例如 Myapp.exe -r 10 将生成10以内(不包括10)

四则运算表达式求值 OpenJ_Bailian - 4132

四则运算表达式求值 OpenJ_Bailian - 4132 题意:设计一个计算器,实现+-*/以及()的表达式运算求值. 栈的应用,这学期学数据结构,手写了栈练一下~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=10010; //最大表达式长度 4 5 template <typename T> 6 class Stack; 7 8 template <typename T> 9

Java的λ表达式(1)

λ表达式的基本用途 回调与Java8的λ表达式 说明了Java8的λ表达式的基本用途:完成了回调的原意--代码的参数化. 回调:可以简单地说,如果你的方法需要override底层或JDK的某个类的方法,而且你从来没有自己调用过该方法,则该方法(有时候,也指被改写的方法)就是回调.例如 Applet定义的init().start().stop()和destroy(): 图形绘制方法paint(Graphics).update(Graphics)和重载的repaint(): java.lang.Ru

Java Lambda表达式入门[转]

原文链接: Start Using Java Lambda Expressions http://blog.csdn.net/renfufei/article/details/24600507 下载示例程序 Examples.zip .原文日期: 2014年4月16日 翻译日期: 2014年4月27日翻译人员: 铁锚简介(译者注:虽然看着很先进,其实Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能.本人建议不要

Java Web表达式注入

原文:http://netsecurity.51cto.com/art/201407/444548.htm 0×00 引言 在2014年6月18日@终极修炼师曾发布这样一条微博: 链接的内容是一个名为Jenkins的服务,可以在没有password的情况下受到攻击.而攻击方法比较有趣,Jenkins提供了一个Script Console功能,可以执行Groovy 脚本语言.下面我们来看下维基百科对于这个脚本语言的解释:  Groovy是Java平台上设计的面向对象编程语言.这门动态语言拥有类似P

数据结构(7)----栈与队列之栈的应用四则运算表达式求值

栈与队列之栈的应用四则运算表达式求值 栈在四则运算表达式求值的应用为逆波兰表达式(后缀表达式) 普通算式(中缀表达式):9 + (3 - 1) * 3 + 10 / 2     ---(1) 逆波兰表达式(后缀表达式):9 3 1 - 3 * + 10 2 /         ---(2) 1:逆波兰表达式的计算规则 从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号,就将处于栈顶的两个数字出栈,进行运算,再把运算结果进栈,一直到最终获得结果.接下来我们以(2)式为例: