中缀表达式转化成后缀表达式(逆波兰表达式)

问题描述

输入一个中缀表达式,将其转换为后缀表达式并输出

思路分析:

  1. 初始化两个栈,符号栈s1,结果栈 s2;
  2. 从左至右,依次遍历表达式;
  3. 遇到数字,直接将数字放到结果栈s2中;
  4. 遇到运算符
    4.1 若是符号栈 s1 中为空,或者当前准备入栈的是左括号 (,直接入栈;
    4.2 若当前准备入栈的运算符的优先级 小于等于 符号栈 s1 栈顶运算符的优先级,则一直遍历这个符号栈,将符号栈的栈顶元素出栈,并入到 s2 栈中,直到遇到一个运算符的优先级大于当前运算符,最后将当前运算符入 s1 栈中;
    4.3 要是准备入符号栈的运算符大于符号栈栈顶元素的优先级,则直接入栈就行。
  5. 遇到右括号 ):
    5.1 要是符号栈 s1 栈顶的元素是左括号 (,直接将左括号出栈即可,然后进行下一个元素判断;
    5.2 要是s1 的栈顶元素不是左括号,遍历 s1,将 s1 栈顶元素出栈,并入到 s2 栈中,直到遇到 栈顶是 左括号的;
  6. 表达式遍历完后,将 s1 剩下的元素,出栈,依次入到 s2 栈中;
  7. 将 s2 栈的内容出栈,并将其逆序输出得到最终结果。

代码实现:

package stack;

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

// 中缀表达式转后缀表达式
public class InfixToSuffix {
    public static void main(String[] args) {
        String inFix = "1+((2+3)*4)-5";
        // 为了方便计算将中缀表达式存放到ArrayList中
        System.out.println("表达式的样子是:" + toInfixExpressionList(inFix));
        List<String> list = toInfixExpressionList(inFix);
        System.out.println("表达式转成后缀表达式的样子:" + parseSuffixExpresssionList(list));
    }

    /**
     *
     * @param str 表示中缀表达式字符串
     * @return  返回中缀表达式 链表
     */
    public static List<String> toInfixExpressionList(String str){
        List<String> list = new ArrayList<>();
        int index = 0;  // 访问字符串下标用的
        String num = "";  // 用于拼接多位数
        do{
            // 判断当前读取的字符是不是数字
            if(!Character.isDigit(str.charAt(index))){  // 当前字符是运算符
                // 如果是运算符直接加入到链表即可
                list.add(str.charAt(index) + "");
                index++;
            }else{  // 当前字符是数字
                // 每次新的数据前都需要将num置空
                num = "";
                // 如果是数字还需要判断是不是多位数
                while(index < str.length() && Character.isDigit(str.charAt(index))){
                    num += str.charAt(index);
                    index++;
                }
                list.add(num);
            }
        }while(index < str.length());
        return list;
    }

    public static List<String> parseSuffixExpresssionList(List<String> list){
        Stack<String> s1 = new Stack<>();  // 用于存放运算符的栈
        // Stack<String> s2 = new Stack<>();  // 用于存放结果的栈
        // 本来用栈存放结果,但是我们在思路分析的时候发现,结果栈并没有出栈的情况,只是在一直拼接
        // 所以我们可以用list来拼接
        // 而且结果栈要最后逆序输出才是最终的结果(入栈顺序和出栈顺序不一样)
        // list 则可以直接输出正确结果结果,不需要逆序
        List<String> s2 = new ArrayList<>();

        // 遍历 中缀表达式链表
        for(String s : list){
            // 判断当前 s 是不是数字,如果是数字,直接加入结果链表
            if(s.matches("\\d+")){  // 是多位数
                s2.add(s);
            }else if(s.equals("(")){   // 是符号
                // 如果是左括号,或者符号栈中没有符号,则直接入栈即可
                s1.push(s);
            }else if(s.equals(")")){
                // 如果是右括号),需要从符号栈中弹出符号,并将弹出的符号入结果链表,直到遇到左括号(,并且最后记得将左括号弹出栈,左右括号不入结果链表
                while(!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                // 运行到这,说明s1 栈顶得元素是左括号,将左括号直接出栈
                s1.pop();
                // 接下来都是运算符了,需要对运算符得优先级进行比较
            } else {  // 是运算符
                // 如果当前的 s 是运算符,需要将 s 与s1 栈顶元素的优先级进行比较
                // 如果当前 s 的优先级 <= 栈顶元素的优先级,需要将栈顶元素弹出 加入 到 结果链表 s2 中
                while(s1.size() != 0 && Operation.getOperation(s1.peek()) >= Operation.getOperation(s)){
                    s2.add(s1.pop());
                }
                // 运行到这一步就说明 s 的优先级已经大于 s1 栈顶元素的优先级了
                s1.push(s);
            }
        }
        while (s1.size() != 0){
            s2.add(s1.pop());
        }
        return s2;
    }
}

// 定义一个符号类,可以用这个类,将符号得优先级输出
class Operation{
    private static final int ADD = 1;
    private static final int SUB = 1;
    private static final int MUL = 2;
    private static final int DIV = 2;

    public static int getOperation(String s){
        int result = 0;
        switch (s){
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = 2;
                break;
            case "/":
                result = 2;
                break;
            default:
                System.out.println("你的运算符有误~");
                result = 0;
                break;
        }
        return result;
    }
}

最终结果:

在这里插入图片描述

利用逆波兰表达式实现计算器

利用逆波兰表达式实现计算器

发布了98 篇原创文章 · 获赞 5 · 访问量 6450

猜你喜欢

转载自blog.csdn.net/weixin_43580746/article/details/105264471