中缀表达式转后缀表达式以及后缀表达式的计算:

示例:中缀表达式:1 + ( ( 2 + 3 )× 4) - 5 =》后缀表达式:1 2 3 + 4 * + 5 -

思路:

  1. 创建两个栈,运算符栈s1 和 数值栈s2。

  2. 从左到右扫描中缀表达式。

  3. 遇到数的话直接假如到数栈s2中

  4. 遇到运算符的话,分为以下几种情况:

    1) 如果s1为空,或者s1的栈顶为左括号 ” (“ 就直接将运算符入栈

    2)如果s1不为空,扫描到的运算符的优先级高于栈顶运算符的优先级的话,也直接入栈

    3)如果s1不为空,扫描到的运算符的优先级小于或等于栈顶运算符的优先级的话,就将s1中的运算符弹出并压入到s2栈中,然后再转到(4.1)与s1中新的栈顶的运算符进行比较。

  5. 遇到括号的情况:

    1)当遇到左括号时,直接入栈

    2)当遇到右括号时,将s1栈中的符号依次弹出并压入到s2中,直到遇见左括号为止。然后将这一对括号丢弃

    6.重复2-5的步骤,直到扫描到表达式的最右边(即表达式最后)

    7.将s1中剩余的运算符依次弹出,并压入到s2中

    8.依次弹出s2中的元素并输出,此时的结果的逆序就是我们要的后缀表达式

后缀表达式的计算:

思路:

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果

例如: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 - , 针对后缀表达式求值步骤如下:

1) 从左至右扫描,将 3 4 压入堆栈;
2) 遇到 + 运算符,因此弹出 4 3 4 为栈顶元素, 3 为次顶元素),计算出 3+4 的值,得 7 ,再将 7 入栈;
3) 5 入栈;
4) 接下来是 × 运算符,因此弹出 5 7 ,计算出 7×5=35 ,将 35 入栈;
5) 6 入栈;

最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

代码:

package com.lzh.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 逆波兰表达式的计算
 */
public class ReversePolandNotation {
    public static void main(String[] args) {
        //定义一个String变量,来接收后缀表达式
        String suffixExpression = "3 4 + 5 * 6 - ";
        //String suffixExpression = "3#4#+#5#x#6#-#";
        String expression = "1+((2+3)*4)-5";//注意表达式(这是一个中缀表达式)
        /**
         * 思路:
         * 1.创建一个ArrayList集合
         * 2.把表达式中的每个字符串分割出来,放到集合中
         * 3.然后把集合传到一个方法中,然后让这个方法进行表达式的计算即可
         */
        List<String> list = getList(suffixExpression);
        int res = calculate(list);
        System.out.println(suffixExpression+"的结果是=>"+res);
       // System.out.println(list);
        //中缀表达式对应的集合
        System.out.println("中缀表达式="+expression);
        List<String> strlist = toInfixExpressionList(expression);
        System.out.println("中缀表达式对应的集合"+strlist);
        //后缀表达式对应的集合
        List<String> sufix = parseSuffixExpression(strlist);
        System.out.println(expression+"对应的后缀表达式为:"+sufix);
        //计算中缀表达式转为后缀表达式的结果
        int r = calculate(sufix);
        System.out.println(expression+"的结果为:"+r);
    }
    //接收一个字符串,把字符串分割后放入到集合中
    public static List<String> getList(String suffixExpression){
        String[] splist = suffixExpression.split(" ");
        //String[] splist = suffixExpression.split("#"); // 用#或者空格分割都可以
        List<String> list = new ArrayList<String>();
        //把分割后的每个字符添加到集合中
        for(String item : splist){
            list.add(item);
        }
        return list;
    }
    //把集合中的元素遍历后,进行计算,然后入栈
    /**
     * 思路:
     * 1.从左到右扫描字符串(这里直接遍历集合就可以了),遇到数字就放入到栈中
     * 2.遇到符号后,从栈中pop出两个数,进行计算,然后把计算的结果放到栈中
     * 3.如此反复,最后栈中的数据就是后缀表达式的结果
     * 注意:这里只需要创建一个栈即可,我们只需要把数字放到栈中,遇到符号就直接计算了。
     */
    public static int calculate(List<String> list){
        //创建一个栈
        Stack<String> stack = new Stack<String>();
        //遍历集合
        for (String item : list){
            //这里使用正则表达式来取出数字
            if (item.matches("\\d+")){ //匹配出是否是数字(多位数也能匹配)
                stack.push(item);
            }else {
                //不是数字的话,就从栈中pop出两个数,进行计算
                //定义变量来接收数据
                int num1 = Integer.parseInt(stack.pop());//接收栈顶的数据
                int num2 = Integer.parseInt(stack.pop());//接收次栈顶的数据
                int res = 0;//用来接收结果
                if (item.equals("+")){
                    res = num1 + num2;
                }else if (item.equals("-")){
                    res = num2 - num1;
                }else if (item.equals("*")){
                    res = num1 * num2;
                }else if (item.equals("/")){
                    res = num2 / num1;
                }else{
                    throw  new RuntimeException("运算符有问题,无法进行计算");
                }
                //计算之后把结果入栈,因为栈是String类型的,这里我们把这个结果拼接一个字符串,就实现了int快速转换成String类型了
                stack.push(""+res);
            }
        }
        //最后栈中的数据就是表达式的结果,我们把这个结果返回就行
        return Integer.parseInt(stack.pop());
    }
    //中缀表达式转换成后缀表达式的方法
    /**
     * 思路:
     * 1.先把给定的字符串表达式扫描出来放到list集合中,这样方便我们后续的操作
     * 2.判断每个字符是运算符还是数字:
     *    2.1 如果是运算符的话就直接放入到list集合中
     *    2.2 如果是数字的话 我们要判断一下这个数是否是一个多位数,如果是多位数,我们把这个数字拼接上之后再放入到list集合中
     * toInfixExpressionList:方法名说明:中缀表达式对应的list集合
     */
    public static List<String> toInfixExpressionList(String expression){
        //先创建一个list集合
        List<String> list = new ArrayList<String>();
        //定义相关变量
        String str ; //用于多位数的拼接
        int i = 0; //一个指针,用来扫描中缀表达式的字符串
        char c; // 用来接收扫描到的每一个字符
        //这里用一个do...while()循环
        do {
            //如果是非数字,直接添加到list集合中
            if((c = expression.charAt(i) ) < 48 || (c = expression.charAt(i)) > 57){
                list.add("" + c);
                i++;//后移
            }else{
                //str每次拼接都重置成""
                str = "";
                //循环拼接多位数,ASCII表中 '0'[48]~'9'[57] 大于等于48~小于等于57是数
                while(i < expression.length() && (c=expression.charAt(i))>=48 && (c = expression.charAt(i))<=57){
                    str += c;
                    i++;//i后移,往后判断是否还有数字
                }
                //拼接完多位数后,把数字放到集合中
                list.add(str);
            }
        }while(i < expression.length());
        return list;
    }
    //中缀表达式转后缀表达式的方法
    public static List<String> parseSuffixExpression(List<String> strList){
        //先创建栈,用来存放符号和数值
        Stack<String> s1 = new Stack<String>();//用来存放符号
        //Stack<String> s2 = new Stack<String>();//用来存放数字
        //因为s2这个栈只有入栈操作 没有出栈操作,到最后还要逆序打印,这里我们可以用一个list集合代替
        List<String> s2 = new ArrayList<String>();
        //从左到右扫描中缀表达式 (即遍历我们传过来的list集合)
        for (String item : strList){
            //如果是一个数,直接加入到s2中
            if (item.matches("\\d+")){//用正则表达式来判断是否是一个数(同时多位数也能判断)
                s2.add(item);
            }else if (item.equals("(")){//当遇到左括号时,直接入栈
                s1.push(item);
            }else if (item.equals(")")){//当遇到右括号时,将s1栈中的符号依次弹出并压入到s2中,直到遇见左括号为止。然后将这一对括号丢弃
                while (!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//!!! 将 ( 弹出 s1栈, 消除小括号
            }else{
                /**
                 *  如果s1不为空,扫描到的运算符的优先级小于或等于栈顶运算符的优先级的话,就将s1中的运算符弹出并压入到s2栈中,然后再转到
                 * (4.1)与s1中新的栈顶的运算符进行比较。
                 *  存在的问题:但是我们还缺少一个比较运算符优先级的方法
                 */
                while(s1.size()!=0 && Operation(item) <= Operation(s1.peek())){
                    s2.add(s1.pop());
                }
                //然后把当前扫描到的运算符压入到s1中
                s1.push(item);
            }
        }
        //将s1中剩余的运算符依次弹出,并压入到s2中
        while(s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;

    }

    //比较运算符优先级的方法
    public static  int Operation(String str){
        int result = 0;//用于返回优先级
        switch (str){
            case "+" :
                result = 1;
                break;
            case "-" :
                result = 1;
                break;
            case "*" :
                result = 2;
                break;
            case "/" :
                result = 2;
                break;
            default:
                result = 0; //如果不是这四个运算符 就默认返回0(比如是括号的时候,就返回0,括号在栈外优先级最高,在栈内优先级最低)
                break;
        }
        return result;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值