中缀表达式转后缀表达式,并计算表达式的结果

前言

我们知道,人和计算机不一样,(1+((2+3)*4)-4)/2,这样一个表达式,对我们来说很好计算,我们直接先算括号里面的,然后在一步一步计算,对于计算机来说,他们不行,因为他们是从一端到另一端挨个扫描的,他们不是去跳着扫描的括号,先计算括号里的值,所以对于计算机来说,他们适合计算后缀表达式,今天我们就使用java来实现传入一个算术表达式,我们将其转换为后缀表达式,并计算出结果的程序。

如何将中缀算术表达式转换为后缀表达式?

第一步:将中缀表达式转换成List

原理分析:
1.我们首先进行对整个表达式进行遍历
2.当遍历到的是数字的时候(matches(“\d+”)是用来匹配是否是数字的正则表达式,是就返回true,否就返回false),此时我们不能直接将数字放入list,因为有可能是多位数,此时你只扫描了第一位数,所以我们往后面看一位
3.使用while循环,在i小于表达式长度且下一位还是数字的时候,将这些数字进行拼接,同时i++,否则外层遍历表达式的for循环会乱,然后还是循环,直至后面一位不是数字时,将拼接的数字放入list中,记得将拼接字符串初始化str=“”,
4.如果不是数字,那么就是个运算符了,我们直接放入list中
代码如下:

    //将中缀表达式转成对应的List
    //s="1+((2+3)*4)-5"
    public static List<String> toInfixExpressionList(String s) {
        //用于多位数拼接
        String str = "";
        List<String> ls = new ArrayList<>();
        //遍历字符串s
        for (int i = 0; i < s.length(); i++) {
            //如果为数字
            if (s.substring(i, i + 1).matches("\\d+")) {
                str = str + s.substring(i, i + 1);
                //循环往后看一位是不是数字,直到非数字,每次都需要i++
                while (i < s.length() - 1 && s.substring(i + 1, i + 2).matches("\\d+")) {
                    str = str + s.substring(i + 1, i + 2);
                    i++;
                }
                //然后把拼接的多位数放入list中,并把str置空,避免下次出现混乱
                ls.add(str);
                str = "";
            } else {
                ls.add(s.substring(i, i + 1));
            }
        }
        return ls;
    }

第二步:写一个方法,返回对应运算符的优先级

因为在中缀表达式转后缀表达式的时候需要比较运算符的优先级,所以这里我们写一个方法进行比较。
这里很简单,我们只需要返回一个数字即可,+ - 我们定义为1,* / 我们定义为2,其他的不考虑,然后返回对应优先级数字即可。
代码如下:

    //写一个方法,返回对应的优先级数字
    public static int getValue(String operation) {
        int result = 0;
        switch (operation) {
            case "+":
                result = 1;
                break;
            case "-":
                result = 1;
                break;
            case "*":
                result = 2;
                break;
            case "/":
                result = 2;
                break;
            default:
                throw new RuntimeException("这不像是一个运算符哦!");
        }
        return result;
    }

第三步:将中缀表达式list转成对应的后缀表达式list

原理分析:
1、初始化一个栈和一个list分别用来存放符号和后缀表达式
2、从左至右扫描中缀表达式
3、遇到操作数时,将其压入list
4、遇到运算符时,比较其与栈顶运算符的优先级
4.1、如果栈为空,或者栈顶运算符为左括号"(“,则直接将此运算符入栈
4.2、否则,若优先级比栈顶运算符的高,也将运算符直接压入栈
4.3、否则,将栈顶的运算符弹出并放入list中,再次转到4.1、与栈中新的栈顶运算符进行比较
5、遇到括号时
5.1、如果是左括号”(“,则直接压入栈
5.2、如果是右括号”)",则依次弹出栈顶的运算符,并放入list,直到遇到左括号为止,此时将这一对括号丢弃
6、重复2至5,直到表达式的最右边
7、将栈中剩余的运算符依次弹出并放入list
8、此时list中就是后缀表达式的list集合
代码如下:

    //方法:将得到的中缀表达式对应的list 转成 后缀表达式对应的List
    public static List<String> parseSuffixExpressionList(List<String> ls) {
        //定义一个栈用来存放符号,再定义一个list用来存放后缀表达式
        Stack<String> s1 = new Stack<>();
        List<String> s2 = new ArrayList<>();
        //遍历ls,扫描中缀表达式
        for (String item : ls) {
            //遇到操作数,直接压入栈
            if (item.matches("\\d+")) {
                s2.add(item);
            } else if (item.equals("(")) {//如果是“(”,则直接压入s1
                s1.push(item);
            } else if (item.equals(")")) {//如果是“)”则依次弹出s1栈顶运算符,并压入s2,直到遇到"("为止,此时这一对括号丢弃
                while (true) {
                    if (s1.peek().equals("(")) {
                        s1.pop();
                        break;
                    } else {
                        s2.add(s1.pop());
                    }
                }
            } else {//遇到运算符,需要与s1栈顶运算符比较
                while (true) {
                    if (s1.isEmpty() || s1.peek().equals("(")) {//为空 或者 栈顶为“(” 直接放入
                        s1.push(item);
                        break;
                    } else if (getValue(item) > getValue(s1.peek())) {//如果优先级比栈顶运算符的高,也将运算符压入s1
                        s1.push(item);
                        break;
                    } else if (getValue(item) <= getValue(s1.peek())) {//优先级小于等于的时候将栈顶放入s2,然后在循环比较运算符
                        s2.add(s1.pop());
                    }
                }
            }
        }
        while (!s1.isEmpty()){
            s2.add(s1.pop());
        }
        return s2;
    }

第三步:将后缀表达式进行计算

原理分析:
从左至右扫面后缀表达式,遇到数字时,将数字压入栈,遇到运算符的时候,弹出栈顶的两个数,用运算符对他们做相应的计算,并将结果入栈:重复上述过程直到表达式最右端,最后运算出的值即为表达式的结果。(注意:栈是先进后出,所以在做-或/运算时,需要拿第二个弹出的运算符去- / 第一个)
代码如下:

   //计算的方法
    public static double calculate(List<String> ls) {
        //创建一个栈,只需要一个栈即可
        Stack<String> stack = new Stack<String>();
        //遍历ls
        for (String item : ls) {
            //匹配的是多位数
            if (item.trim().matches("\\d+")) {
                //入栈
                stack.push(item.trim());
            } else {
                //pop出两个数,并运算,再入栈
                double num1 = Double.parseDouble(stack.pop());
                double num2 = Double.parseDouble(stack.pop());
                double res = 0;
                if (item.trim().equals("+")) {
                    res = num1 + num2;
                } else if (item.trim().equals("-")) {
                    res = num2 - num1;
                } else if (item.trim().equals("*")) {
                    res = num1 * num2;
                } else if (item.trim().equals("/")) {
                    res = num2 / num1;
                } else {
                    throw new RuntimeException("运算符有错误");
                }
                //把res 入栈
                stack.push("" + res);
            }
        }
        //最后留在stack中的数据是运算结果
        return Double.parseDouble(stack.pop());
    }

运算结果如下:

(1+((2+3)*4)-4)/2=8.5

源码

package com.haot.stack;

import java.util.*;

public class PolandNotation {
    public static void main(String[] args) {
        //定义一个算数表达式
        String s1 = "(1+((2+3)*4)-4)/2";
        List<String> infixExpressionList = toInfixExpressionList(s1);
        List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);
        double calculate = calculate(suffixExpressionList);
        System.out.println(s1+"="+calculate);
    }

    //将中缀表达式转成对应的List
    //s="1+((2+3)*4)-5"
    public static List<String> toInfixExpressionList(String s) {
        //用于多位数拼接
        String str = "";
        List<String> ls = new ArrayList<>();
        //遍历字符串s
        for (int i = 0; i < s.length(); i++) {
            //如果为数字
            if (s.substring(i, i + 1).matches("\\d+")) {
                str = str + s.substring(i, i + 1);
                //循环往后看一位是不是数字,直到非数字,每次都需要i++
                while (i < s.length() - 1 && s.substring(i + 1, i + 2).matches("\\d+")) {
                    str = str + s.substring(i + 1, i + 2);
                    i++;
                }
                //然后把拼接的多位数放入list中,并把str置空,避免下次出现混乱
                ls.add(str);
                str = "";
            } else {
                ls.add(s.substring(i, i + 1));
            }
        }
        return ls;
    }

    //方法:将得到的中缀表达式对应的list 转成 后缀表达式对应的List
    public static List<String> parseSuffixExpressionList(List<String> ls) {
        //定义一个栈用来存放符号,再定义一个list用来存放后缀表达式
        Stack<String> s1 = new Stack<>();
        List<String> s2 = new ArrayList<>();
        //遍历ls,扫描中缀表达式
        for (String item : ls) {
            //遇到操作数,直接压入栈
            if (item.matches("\\d+")) {
                s2.add(item);
            } else if (item.equals("(")) {//如果是“(”,则直接压入s1
                s1.push(item);
            } else if (item.equals(")")) {//如果是“)”则依次弹出s1栈顶运算符,并压入s2,直到遇到"("为止,此时这一对括号丢弃
                while (true) {
                    if (s1.peek().equals("(")) {
                        s1.pop();
                        break;
                    } else {
                        s2.add(s1.pop());
                    }
                }
            } else {//遇到运算符,需要与s1栈顶运算符比较
                while (true) {
                    if (s1.isEmpty() || s1.peek().equals("(")) {//为空 或者 栈顶为“(” 直接放入
                        s1.push(item);
                        break;
                    } else if (getValue(item) > getValue(s1.peek())) {//如果优先级比栈顶运算符的高,也将运算符压入s1
                        s1.push(item);
                        break;
                    } else if (getValue(item) <= getValue(s1.peek())) {//优先级小于等于的时候将栈顶放入s2,然后在循环比较运算符
                        s2.add(s1.pop());
                    }
                }
            }
        }
        while (!s1.isEmpty()){
            s2.add(s1.pop());
        }
        return s2;
    }

    //写一个方法,返回对应的优先级数字
    public static int getValue(String operation) {
        int result = 0;
        switch (operation) {
            case "+":
                result = 1;
                break;
            case "-":
                result = 1;
                break;
            case "*":
                result = 2;
                break;
            case "/":
                result = 2;
                break;
            default:
                throw new RuntimeException("这不像是一个运算符哦!");
        }
        return result;
    }

    //计算的方法
    public static double calculate(List<String> ls) {
        //创建一个栈,只需要一个栈即可
        Stack<String> stack = new Stack<String>();
        //遍历ls
        for (String item : ls) {
            //匹配的是多位数
            if (item.trim().matches("\\d+")) {
                //入栈
                stack.push(item.trim());
            } else {
                //pop出两个数,并运算,再入栈
                double num1 = Double.parseDouble(stack.pop());
                double num2 = Double.parseDouble(stack.pop());
                double res = 0;
                if (item.trim().equals("+")) {
                    res = num1 + num2;
                } else if (item.trim().equals("-")) {
                    res = num2 - num1;
                } else if (item.trim().equals("*")) {
                    res = num1 * num2;
                } else if (item.trim().equals("/")) {
                    res = num2 / num1;
                } else {
                    throw new RuntimeException("运算符有错误");
                }
                //把res 入栈
                stack.push("" + res);
            }
        }
        //最后留在stack中的数据是运算结果
        return Double.parseDouble(stack.pop());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值