Java实现中缀表达式转后缀表达式

1.后缀表达式介绍

1.1简介

逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)
在实现中缀转后缀之前我们先了解后缀表达式的实现,学习过编译原理这门的课程的同学,应该对逆波兰式非常的熟悉哈,没错他就是后缀表达式。

1.2实现逆波兰计算器

  • 输入一个逆波兰表达式,使用栈stack,计算其结果
  • 只支持对整数的计算

1.3思路分析

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

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

  • 从左至右扫描,将3和4压栈
  • 遇到 “+” 运算符,弹出 栈顶元素和次栈顶元素 , 3和4,通过运算符 计算 3+4,得到7,再将7入栈
  • 将5入栈
  • 遇到“✖” 运算符,弹出 5 和 7,计算 5* 7 = 35,将35 入栈
  • 将 6 入栈
  • 遇到“-”运算符,计算出 35-6得29,最终结果29

1.4代码实现

import java.util.Arrays;
import java.util.List;
import java.util.Stack;

/**
* @author 尹稳健~
* @version 1.0
* @time 2022/8/29
*/
public class PolandNotation {
   public static void main(String[] args) {
       // 定义一个人逆波兰式  3 4 + 5 * 6 -
       String express = "3 4 + 5 * 6 - ";
       // 将 逆波兰式转为一个list数组
       List<String> stringList = Arrays.asList(express.split(" "));
       int result = calculate(stringList);
       System.out.println(result);

   }

   public static int calculate(List<String> list){
       // 创建一个栈存放数字
       Stack<String> stack = new Stack<>();
       // 遍历将 数字放入栈
       for (String item : list) {
           // 正则表达式匹配数字,可能数字是多位数
           if (item.matches("\\d+")){
               stack.push(item);
               // 如果不是数字那么就弹出栈顶两个元素通过运算符计算
           }else{
               // 定义一个变量存放计算结果
               Integer result;
               // 栈顶元素
               Integer rear = Integer.parseInt(stack.pop());
               // 次顶元素
               Integer front = Integer.parseInt(stack.pop());
               // 判断item是哪个运算符
               if ("+".equals(item)){
                   result = front + rear;
               }else if ("-".equals(item)){
                   result = front - rear;
               }else if ("*".equals(item)){
                   result = front * rear;
               }else{
                   result = front / rear;
               }
               // 计算完将数据存入栈顶
               stack.push(String.valueOf(result));
           }
       }
       return Integer.parseInt(stack.pop());
   }

}

2.中缀转后缀表达式

2.1 思路分析

  • 初始化一个数组存放表达式,一个栈存放运算符
  • 从左至右扫描中缀表达式,遇到数字直接添加到数组表达式
  • 遇到运算符时,需要判断
    • 如果是 “(” 直接入栈
    • 如果是 “)” ,则依次弹出栈顶的元素,压入数组中,直到遇到 “(” 时结束,且需要将 “(” 弹栈,
    • 遇到 + - * / 运算符时,需要判断运算符的优先级,如果入栈元素小于等于栈顶元素的优先级时,需要将栈顶元素压入数组中,然后入栈元素再次进行运算符优先级比较
  • 如果中缀表达式已经读取完毕,则将栈中的元素依次出栈,放入数组中

2.2图解

当遇到“)”右括号要入栈时
在这里插入图片描述
弹出符号栈的栈顶元素,直到遇到 “(”左括号为止,并且弹出左括号
在这里插入图片描述
得到
在这里插入图片描述
当减号“-”要入栈时
在这里插入图片描述
入栈元素“-”和符号栈的栈顶元素进行优先级比较,入栈元素优先集不大于符号栈栈顶元素,将符号栈栈顶元素存放到后缀表达式的数组中,然后“-”入符号栈
在这里插入图片描述
得到
在这里插入图片描述
最后将符号栈的元素依次pop到后缀表达式中,得到:

在这里插入图片描述

2.3代码实现

package com.sky.stackTest;

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

/**
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/8/29
 */
public class PolandNotation {
    public static void main(String[] args) {
        // 定义一个人逆波兰式  3 4 + 5 * 6 -
        String express = "3 4 + 5 * 6 - ";
        // 将 逆波兰式转为一个list数组
        List<String> stringList = Arrays.asList(express.split(" "));
        int result = calculate(stringList);
        System.out.println(result);

        // 完成将一个中缀转后缀的功能
        express = "1+((2+3)*4)-5";
        // 得到中缀表达式转为的List
        List<String> strings = toInfixExpression(express);
        // 将List转为后缀表达式
        List<String> parse = parse(strings);
        System.out.println(parse);
    }

    /**
     * 后缀表达式求值
     */
    public static int calculate(List<String> list) {
        // 创建一个栈存放数字
        Stack<String> stack = new Stack<>();
        // 遍历将 数字放入栈
        for (String item : list) {
            // 正则表达式匹配数字,可能数字是多位数
            if (item.matches("\\d+")) {
                stack.push(item);
                // 如果不是数字那么就弹出栈顶两个元素通过运算符计算
            } else {
                // 定义一个变量存放计算结果
                Integer result;
                // 栈顶元素
                Integer rear = Integer.parseInt(stack.pop());
                // 次顶元素
                Integer front = Integer.parseInt(stack.pop());
                // 判断item是哪个运算符
                if ("+".equals(item)) {
                    result = front + rear;
                } else if ("-".equals(item)) {
                    result = front - rear;
                } else if ("*".equals(item)) {
                    result = front * rear;
                } else {
                    result = front / rear;
                }
                // 计算完将数据存入栈顶
                stack.push(String.valueOf(result));
            }
        }
        return Integer.parseInt(stack.pop());
    }

    /**
     * 将中缀表达式转为List
     */
    public static List<String> toInfixExpression(String string) {
        // 索引
        int index = 0;
        // 创建一个数组保存
        List<String> ls = new ArrayList<>();
        while (index < string.length()) {
            // 如果是字符那么就直接添加
            if (string.charAt(index) < 48 || string.charAt(index) > 57) {
                ls.add(string.charAt(index) + "");
                index++;
            } else {
                String str = "";
                // 判断数字是否是多位数,直到匹配不到数字结束循环
                while (index < string.length() && (string.charAt(index) >= 48 && string.charAt(index) <= 57)) {
                    // 拼接
                    str += string.charAt(index) + "";
                    index++;
                }
                ls.add(str);
            }
        }
        return ls;

    }

    public static List<String> parse(List<String> list) {
        // 符号栈
        Stack<String> s1 = new Stack<>();
        // 后缀表达式
        ArrayList<String> s2 = new ArrayList<>();
        for (String s : list) {
            // 遇到操作数直接压入s2
            if (s.matches("\\d+")) {
                s2.add(s);
                // 遇到(直接压入s1
            } else if ("(".equals(s)) {
                s1.push(s);
                // 依次弹出s1栈顶的运算符压入s2,知道遇到左括号为止
            } else if (")".equals(s)) {
                while (!"(".equals(s1.peek())) {
                    // 压入s2
                    s2.add(s1.pop());
                }
                // 遇到(时,将(移除s1
                s1.pop();
            }else{
                // 判断运算符的优先级
                while (s1.size() != 0 &&getNum(s1.peek()) >= getNum(s)){
                    s2.add(s1.pop());
                }
                s1.push(s);
            }
        }
        // 将s1中剩余的运算符加入到s2
        while (s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;

    }

    /** 根据运算符返回值,值越大,优先集越高 */
    public static int getNum(String string){
        if ("*".equals(string) || "/".equals(string)){
            return 2;
        }else if ("+".equals(string) || "-".equals(string)){
            return 1;
        }else{
            return 0;
        }
    }
}



  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕竟尹稳健

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值