文章目录
问题描述
输入一个中缀表达式,将其转换为后缀表达式并输出
思路分析:
- 初始化两个栈,符号栈s1,结果栈 s2;
- 从左至右,依次遍历表达式;
- 遇到数字,直接将数字放到结果栈s2中;
- 遇到运算符:
4.1 若是符号栈 s1 中为空,或者当前准备入栈的是左括号 (,直接入栈;
4.2 若当前准备入栈的运算符的优先级 小于等于 符号栈 s1 栈顶运算符的优先级,则一直遍历这个符号栈,将符号栈的栈顶元素出栈,并入到 s2 栈中,直到遇到一个运算符的优先级大于当前运算符,最后将当前运算符入 s1 栈中;
4.3 要是准备入符号栈的运算符大于符号栈栈顶元素的优先级,则直接入栈就行。 - 遇到右括号 ):
5.1 要是符号栈 s1 栈顶的元素是左括号 (,直接将左括号出栈即可,然后进行下一个元素判断;
5.2 要是s1 的栈顶元素不是左括号,遍历 s1,将 s1 栈顶元素出栈,并入到 s2 栈中,直到遇到 栈顶是 左括号的; - 表达式遍历完后,将 s1 剩下的元素,出栈,依次入到 s2 栈中;
- 将 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;
}
}