首页 > 技术文章 > Java实现将中缀表达式转换到后缀表达式

seizedays 2020-04-05 15:28 原文

思路:

1.初始化两个栈 运算符栈 s1 和储存中间结果栈 s2
2. 从左到右扫描中缀表达式
3. 遇到操作数时 压入s2
4. 遇到操作符 o1 时 比较其与 S1 栈顶运算符的优先级
1)如果s1为空 或栈顶运算符为左括号 '(' 则直接将此运算符入栈
2)如果优先级高于栈顶,也直接压如运算符栈 s1
3)如果优先级低于栈顶运算符 将栈顶运算符弹出 压入s2 再次将o1与s1中的栈顶运算符比较
5.遇到括号时
1)如果是左括号'('直接压入s1
2)如果是右括号')' 则一次弹出s1栈顶的运算符,并压入s2 直到遇到左括号位置,然后将这一对括号丢弃
6.重复步骤2-5直到扫描完表达式全部内容
7.将s1中剩余内容全部依次弹出并压入s2
8.依次弹出s2中的所有元素并输出 结果的逆序即为转化后的后缀表达式
package com.seizedays.stack;

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

public class PostfixExpression {
    public static void main(String[] args) {
        //完成中缀表达式向后缀表达式的转换
        String expression = "1+((2+3)*4)-5";
        List<String> ls1 = toInfixExpressionList(expression);
        System.out.println("中缀表达式对应的list: " +ls1); //=> ArrayList [1, +, (, (, 2, +, 3, ), *, 4, ), -, 2]
        List<String> suffixExpressionList = parseSuffixExpreesionList(ls1);
        System.out.println("后缀表达式对应的list: " + suffixExpressionList);
    }

    //获取中缀表达式的数组
    public static List<String> toInfixExpressionList(String s){
        List<String> ls = new ArrayList<>();
        int i = 0; // 遍历的指针
        StringBuilder str; // 用于多位数的拼接
        char c; //存放遍历到的字符
        do{
            //如果c是一个非数字,就需要加入到ls中去
           if ((c = s.charAt(i)) < 48 || (c=s.charAt(i)) > 57){
               ls.add("" + c);
               i++;
           }else {
               //如果是一个数字 需要考虑多位数的问题
               str = new StringBuilder();
               while (i < s.length() && (c=s.charAt(i))>=48 && (c=s.charAt(i))<=57){
                   str.append(c); //拼接
                   i++;
               }
               ls.add(str.toString());
           }
        }while (i < s.length());

        return ls;
    }

    //将中缀表达式转换为对应的后缀表达式
    public static List<String> parseSuffixExpreesionList(List<String> ls){
        //定义两个栈
        Stack<String> s1 = new Stack<>(); //符号栈
        //因为s2的栈在整个转换过程中没有pop操作 而且后边要逆序输出
        //因此直接使用List来替代
        List<String> s2 = new ArrayList<>(); //中间结果栈

        //遍历ls
        for(String item : ls){
            //如果是一个数,加入到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 {
                //当item小于等于s1栈顶运算符的优先级的时候 将s1栈顶的运算符弹出 加入到s2中
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                //将item压入栈顶
                s1.push(item);
            }
        }
        //将s1中剩余的运算符依次压入s2
        while (s1.size() != 0){
            s2.add(s1.pop());
        }
        return s2; //因为是存放到一个list中,因此按顺序输出就是对应的逆波兰表达式
    }
}

//编写一个类 用于比较运算符的优先级
class Operation{
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;
    //写一个方法 返回对应的优先级
    public static int getValue(String operation){
        int result = 0;
        switch (operation){
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = MUL;
                break;
            case "/":
                result = DIV;
                break;
            default:
                System.out.println("不能存在该运算符");
                break;
        }

        return result;
    }

}

推荐阅读