中缀表达式转后缀表达式(逆波兰表达式) - 数据结构复习笔记
问题:在之前写的笔记中描述了前缀 / 中缀 / 后缀表达式的一些基本概念和 后缀表达式运算的JAVA代码实现,那么如何将我们平时用到的中缀表达式转换成比较容易进行计算机计算的后缀表达式呢?
前文连接:前缀 / 中缀 / 后缀表达式(逆波兰表达式求值的JAVA写法)
https://blog.csdn.net/No1anWan6/article/details/109469563
中缀 - 后缀表达式的转化
先把转换思路写下来:
- 从左到右遍历中缀表达式,如果遍历的是操作数,那么直接将其输出
- 如果是操作符,如果栈为空,那么将此操作符压入栈中:
- 如果操作符是左括号,那么将其优先值设为最低,并压入栈中
- 如果操作符是右括号,那么直接将栈中的操作符弹出并输出,一直到左括号的弹出(左括号弹出但并不输出)
- 如果是普通操作符(加减乘除),那么先比较与栈顶操作符的优先级,如果该操作符优先级大于栈顶优先级,那么压入栈中,如果小于或等于栈顶元素优先级,那么弹出并输出栈顶操作符,直到遇到比该操作符优先级高的栈顶操作符,并压入栈中。
- 如果我们读到了输入的末尾,则将栈中所有元素依次弹出
验证
以 1 + (( 2 + 3 )x 4 )- 5 为例 :
从左到右遍历:
1,直接输出:Stack: / Output:1
+,压入栈中:Stack:+ / Output:1
(,压入栈中:Stack: ( + / Output:1
(,压入栈中:Stack: ( ( + / Output:1
2,直接输出:Stack: ( ( + / Output:1 2
+,优先级大于栈顶元素,压入栈中:Stack: + ( ( + / Output:1 2
3,直接输出:Stack: + ( ( + / Output:1 2 3
), 弹出并输出栈元素直到遇到左括号:Stack: ( + / Output:1 2 3 +
x,优先级大于栈顶元素,压入栈中:Stack: x ( + / Output:1 2 3 +
4,直接输出:Stack: x ( + / Output:1 2 3 + 4
), 弹出并输出栈元素直到遇到左括号:Stack: + / Output:1 2 3 + 4 x
-,优先级等于栈顶元素,弹出并输出栈顶元素,此时栈空,压入-:Stack: - / Output:1 2 3 + 4 x +
5,直接输出:Stack: - / Output:1 2 3 + 4 x + 5
此时遍历完毕,弹出并输出栈中元素:Stack: - / Output:1 2 3 + 4 x + 5 -
则,后缀表达式为 1 2 3 + 4 x + 5 -
;
JAVA代码实现
public static String tosuffixExpression(String s) {
StringBuffer sb = new StringBuffer();
Stack<Character> stack = new Stack<>();
int index = 0;
while(index < s.length()) {
if(s.charAt(index) == ' ') {
index++;
continue;
}
else if(isNums(s.charAt(index))) {
StringBuffer tmpStr = new StringBuffer();
while(index < s.length() && isNums(s.charAt(index))) {
tmpStr.append(s.charAt(index++));
}
sb.append(tmpStr + " ");
}
else if(isLeft(s.charAt(index))) {
stack.push(s.charAt(index++));
}
else if(isRight(s.charAt(index))) {
char op = stack.pop();
while(!isLeft(op)) {
sb.append(op + " ");
op = stack.pop();
}
index++;
}
else if(isOps(s.charAt(index))) {
if(!stack.isEmpty()) {
if(checkPriority(s.charAt(index),stack.peek())) {
//优先级大于栈顶操作符
stack.push(s.charAt(index++));
}
else {
//优先级小于或等于栈顶操作符
while(!stack.isEmpty() && !checkPriority(s.charAt(index),stack.peek())) {
sb.append(stack.pop()+" ");
}
stack.push(s.charAt(index++));
}
}
else {
stack.push(s.charAt(index++));
}
}
}
while(!stack.isEmpty()) {
sb.append(stack.pop() + " ");
}
return sb.toString();
}
public static boolean checkPriority(char op1,char op2) {
if(op2 == 40) {
return true;
}
int op1P = op1 == '*' || op1 == '/'? 2 : 1;
int op2P = op2 == '*' || op2 == '/'? 2 : 1;
return op1P > op2P;
}
public static boolean isNums(char c) {
if(c <= 57 && c >= 48) {
return true;
}
return false;
}
public static boolean isOps(char c) {
if(c == '+' || c == '-'|| c == '*'|| c == '/') {
return true;
}
return false;
}
public static boolean isLeft(char c) {
if(c == 40) {
return true;
}
return false;
}
public static boolean isRight(char c) {
if(c == 41) {
return true;
}
return false;
}
附上一段自己写的Java的Demo,用来计算给出一个中缀表达式,转为后缀表达式后求求值:
import java.util.ArrayList;
import java.util.Stack;
public class PolandCalculator {
public static void main(String[] args) {
// TODO Auto-generated method stub
//定义逆波兰表达式
//数字之间用空格隔开
String suffixExpression = "3 4 + 5 * 6 -";
System.out.println(polandCalculator(suffixExpression));
System.out.println("-------------");
String inffixExpression = "((5+10/2)+1)*2-1";
System.out.println(tosuffixExpression(inffixExpression));
System.out.println(polandCalculator(tosuffixExpression(inffixExpression)));
}
public static String tosuffixExpression(String s) {
StringBuffer sb = new StringBuffer();
Stack<Character> stack = new Stack<>();
int index = 0;
while(index < s.length()) {
if(s.charAt(index) == ' ') {
index++;
continue;
}
else if(isNums(s.charAt(index))) {
StringBuffer tmpStr = new StringBuffer();
while(index < s.length() && isNums(s.charAt(index))) {
tmpStr.append(s.charAt(index++));
}
sb.append(tmpStr + " ");
}
else if(isLeft(s.charAt(index))) {
stack.push(s.charAt(index++));
}
else if(isRight(s.charAt(index))) {
char op = stack.pop();
while(!isLeft(op)) {
sb.append(op + " ");
op = stack.pop();
}
index++;
}
else if(isOps(s.charAt(index))) {
if(!stack.isEmpty()) {
if(checkPriority(s.charAt(index),stack.peek())) {
//优先级大于栈顶操作符
stack.push(s.charAt(index++));
}
else {
//优先级小于或等于栈顶操作符
while(!stack.isEmpty() && !checkPriority(s.charAt(index),stack.peek())) {
sb.append(stack.pop()+" ");
}
stack.push(s.charAt(index++));
}
}
else {
stack.push(s.charAt(index++));
}
}
}
while(!stack.isEmpty()) {
sb.append(stack.pop() + " ");
}
return sb.toString();
}
public static boolean checkPriority(char op1,char op2) {
if(op2 == 40) {
return true;
}
int op1P = op1 == '*' || op1 == '/'? 2 : 1;
int op2P = op2 == '*' || op2 == '/'? 2 : 1;
return op1P > op2P;
}
public static boolean isNums(char c) {
if(c <= 57 && c >= 48) {
return true;
}
return false;
}
public static boolean isOps(char c) {
if(c == '+' || c == '-'|| c == '*'|| c == '/') {
return true;
}
return false;
}
public static boolean isLeft(char c) {
if(c == 40) {
return true;
}
return false;
}
public static boolean isRight(char c) {
if(c == 41) {
return true;
}
return false;
}
public static int polandCalculator(String s) {
//将字符串用空格分割
String[] split = s.split(" ");
ArrayList<String> expression = new ArrayList<>();
//将每一个元素加入到ArrayList中
for(String str : split) {
if(str != "") {
expression.add(str);
}
}
Stack<Integer> nums = new Stack<>();
//遍历ArrayList,进行计算
for(String elems : expression) {
if(isNum(elems)) {
nums.push(Integer.parseInt(elems));
}
else {
int num2 = nums.pop();
int num1 = nums.pop();
nums.push(compute(num1,num2,elems));
}
}
return nums.pop();
}
public static int compute(int num1, int num2,String op) {
switch(op) {
case "+" : return num1 + num2;
case "-" : return num1 - num2;
case "*" : return num1 * num2;
case "/" : return num1 / num2;
}
throw new RuntimeException("操作符非法");
}
public static boolean isNum(String s) {
if(s.matches("\\d+")) return true;
return false;
}
}