Java 实现 中缀表达式(波兰表达式)转后缀表达式(逆波兰表达式)

中缀表达式转后缀表达式的思路分析步骤

  1. 初始化两个栈 : 运算符栈 s1 和 储存中间结果的栈 s2;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时, 将其压 s2;
  4. 遇到运算符时, 比较其与 s1 栈顶运算符的优先级
    4.1 如果s1为空, 或栈顶运算符为左括号"(", 则直接将此运算符入栈
    4.2 否则, 若优先级比栈顶运算符的高, 也将运算符压入 s1;
    4.3 否则, 将s1栈顶的运算符弹出并压入s2中, 再次转到(4.1)与s1中断的栈顶运算符相比较;
  5. 遇到括号时:
    5.1 如果是左括号"(", 则直接压入 s1
    5.2 如果是右括号")", 则依次弹出 s1栈顶的运算符, 并压入 s2, 直到遇到左括号为止, 此时将这一对括号丢弃
  6. 重复步骤 2–5, 直到表达式的最右边
  7. 将s1中剩余的运算符依次弹出并压入s2
  8. 依次弹出 s2 中的元素并输出, 结果的逆序即为中缀表达式对应的后缀表达式

这里括号并不是运算符

代码实现:

package com.beyond.stack;

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

public class PolandNotationConversion {
    
    

	public static void main(String[] args) {
    
    
		// 完成一个中缀表达式转成后缀表达式的功能
		// 说明
		// 1. 1+((2+3)*4)-5 => 1 2 3 + 4 * + 5 -
		// 2. 因为直接对字符串操作不方便, 因此先将 "1+((2+3)*4)-5" 转成一个 中缀的 List
		// 即 "1+((2+3)*4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]

		System.out.println(toInfixExpressionList("1+((2+3)*4)-5"));
		System.out.println("-------------------------");
		List<String> s1 = toInfixExpressionList("1+((2+3)*4)-5");
		System.out.println(parseSuffixExpressionList(s1));
	}

	// 将中缀表达式转成对应的中缀List
	public static List<String> toInfixExpressionList(String s) {
    
    
		// 定义一个 List 存放对应的内容
		List<String> ls = new ArrayList<String>();
		int i = 0; // 这相当于一个指针, 用于遍历 中缀表达式字符串
		String str; // 对多位数的拼接
		char c; // 每遍历到一个字符就放入 List
		do {
    
    
			if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {
    
    
				ls.add(String.valueOf(c));
				i++;
			} else {
    
     // 如果是一个数, 则需要考虑多位数的问题
				str = ""; // 先将 str 置空
				while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {
    
    
					str += c; // 进行拼接
					i++;
				}
				ls.add(str);
			}
		} while (i < s.length());
		return ls;
	}

	public static List<String> parseSuffixExpressionList(List<String> ls) {
    
    
		// 1. 定义两个栈
		Stack<String> s1 = new Stack<String>(); // 符号栈

		// 说明: 因为 s2 在整个转换过程中没有pop操作, 而且后面还需要逆序输出, 因此比较麻烦, 因此选用 arrayList 来替代
		// Stack<String> s2 = new Stack<String>(); // 存放中间结果
		List<String> s2 = new ArrayList<String>();

		// 遍历 ls
		for (String item : ls) {
    
    
			// 如果是一个数字, 则直接入 s2
			if (item.matches("\\d+")) {
    
    
				s2.add(item);
			} else if (item.equals("(")) {
    
    
				s1.push(item);
			} else if (item.equals(")")) {
    
    
				while (true) {
    
    
					if (s1.peek().equals("(")) {
    
    
						break;
					}
					s2.add(s1.pop());
				}
				s1.pop();
			} else {
    
    
				// 当item的优先级小于等于s1栈顶运算符的优先级, 将s1栈顶的运算符弹出并且加入到s2中, 再次转到s1中比较
				// 问题 : 我们缺少一个比较优先级高低的方法
				while (s1.size() != 0 && (Operation.getValue(s1.peek()) >= Operation.getValue(item))) {
    
    
					s2.add(s1.pop());
				}
				s1.push(item);
			}
		}

		// 将 s1 最后的符号 加入 s2
		while (s1.size() != 0) {
    
    
			s2.add(s1.pop());
		}

		return s2; // 注意因为是存放到了List 中, 所以不用逆序输出了
	}
}

// 编写一个类 Operation 可以返回一个运算符对应的优先级
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;
		}
		return result;
	}
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Beyond_Nothing/article/details/112103391