X16数据结构部分04
中缀表达式转后缀表达式实现思路
/*
中缀表达式
转后缀表达式
思路分析
比较麻烦
需要耐心分析
案例
1 + ( ( 2 + 3 ) * 4 ) - 5
预期结果:16
*/
/*
详细步骤
1. 创建两个栈,一个存放运算符,一个存放中间结果,中间结果就是计算过后的数字栈
2. 从左至右扫描中缀表达式
3. 遇到数字时,压入栈s2
4. 遇到运算符时,比较与栈顶运算符的优先级
a. 栈顶为空或栈顶为左括号,直接将该运算符入栈1
b. 优先级高于栈顶元素,也将运算符压入s1栈中
c. 否则,如果栈顶是小括号类的非运算符,压入栈s1
如果优先级一样,直接弹出s1栈顶元素,并压入s2中,并重新回到a的判断
我认为这里是算法实现的关键
5. 遇到括号时
a. 左括号直接入栈
b. 右括号的话,依次弹出s1的运算符,直到遇到左括号为止
再把左括号弹出,做完这些步骤后继续循环
6. 扫描结束后,将s1剩余运算符依次弹出并压入s2
7. 依次弹出s2元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
还有一个人工中缀转后缀
后缀:把运算符号移动到对应的括号后面,然后再去掉小括号
*/
中缀转后缀辅助方法
/**
* 字符串表达式转ArrayList集合
* @param string 字符串表达式
* @return ArrayList集合
*/
public static List<String> stringExpressionToArrayList(String string){ // 1+((2+3)*4)-5
/*
初始化数据
*/
List<String> stringList = new ArrayList<>(); // 定义结果集
String str; // 多位数拼接
int index = 0; // 遍历字符串
char c; // 遍历到的字符
do {
if ((c = string.charAt(index)) < 48 || (c = string.charAt(index)) > 57){
/*
程序运行到此处
说明c不是一个数字
直接加入stringList集合就行
*/
stringList.add("" + c);
index++;
}else{
/*
程序运行到此处
说明c是一个数字
这个时候需要考虑多位数
并且需要判断后一位是否
已经走到了表达式最后
*/
str = "";
while (index < string.length() && (c = string.charAt(index)) >= 48 && (c = string.charAt(index)) <= 57){
/*
程序运行到此处
说明是多位数
需要进行拼接
*/
str += c;
index++;
}
/*
程序运行到此处
说明拼接完毕
或者说本来就是1位数
直接加进去就行
*/
stringList.add(str);
}
}while (index < string.length());
/*
程序运行到此处
说明扫描完毕
直接返回集合即可
*/
return stringList;
}
中缀转后缀完整代码
package dc;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* @author 404小恐龙
* @version 1.8
* @date 2021/10/8 15:04
*/
public class d19 {
/*
详细步骤
1. 创建两个栈,一个存放运算符,一个存放中间结果,中间结果就是计算过后的数字栈
2. 从左至右扫描中缀表达式
3. 遇到数字时,压入栈s2
4. 遇到运算符时,比较与栈顶运算符的优先级
a. 栈顶为空或栈顶为左括号,直接将该运算符入栈1
b. 优先级高于栈顶元素,也将运算符压入s1栈中
c. 否则,如果栈顶是小括号类的非运算符,压入栈s1
如果优先级一样,直接弹出s1栈顶元素,并压入s2中,并重新回到a的判断
我认为这里是算法实现的关键
5. 遇到括号时
a. 左括号直接入栈
b. 右括号的话,依次弹出s1的运算符,直到遇到左括号为止
再把左括号弹出,做完这些步骤后继续循环
6. 扫描结束后,将s1剩余运算符依次弹出并压入s2
7. 依次弹出s2元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
*/
public static void main(String[] args) {
/*
中缀表达式
转后缀表达式
案例
1+((2+3)*4)-5
预期结果:1 2 3 + 4 * + 5 -
代码实现注意点
由于对字符串操作不太方便,所以先转成ArrayList集合的形式
*/
List<String> stringList = stringExpressionToArrayList("1+((2+3)*4)-5");
System.out.println(stringList); // [1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
List<String> stringList1 = convertInfixExpressionToPostfixExpression(stringList);
System.out.println(stringList1); // [1, 2, 3, +, 4, *, +, 5, -]
}
/**
* 中缀表达式转后缀表达式
* @param stringList 中缀表达式对应List集合
* @return 后缀表达式对应List集合
*/
public static List<String> convertInfixExpressionToPostfixExpression(List<String> stringList){
/*
初始化数据
定义两个栈
一个存放运算符
一个存放结果
但由于结果栈从未弹栈
并且最后还需要逆序输出
所以完全可以用ArrayList替代
*/
Stack<String> operatorStack = new Stack<>();
List<String> resultStack = new ArrayList<>();
/*
程序核心部分
扫描遍历stringList
*/
for (String s : stringList) {
if (s.matches("\\d+")){
/*
程序运行到此处
说明集合元素是一个数字
直接入栈
*/
resultStack.add(s);
}else if (s.equals("(")){
/*
程序运行到此处
说明扫描到左括号
直接入栈
*/
operatorStack.push(s);
}else if (s.equals(")")){
/*
程序运行到此处
说明扫描到的是右括号
现在依次弹出运算符栈的元素
*/
while(!operatorStack.peek().equals("(")){
/*
程序运行到此处
说明还没看到左括号
这个时候继续弹栈
*/
resultStack.add(operatorStack.pop());
}
/*
程序运行到此处
说明看到了左括号
弹出左括号
*/
operatorStack.pop();
}else {
/*
程序运行到此处
说明扫描到运算符
需要做优先级判断
*/
while (operatorStack.size() != 0 && OperatorPrecedence.getPriorityNumber(operatorStack.peek()) >= OperatorPrecedence.getPriorityNumber(s)){
/*
程序运行到此处
说明栈顶优先级高于或等于当前优先级
此时需要弹出s1栈顶元素并加入到s2
完成此操作后继续重复同样操作
*/
resultStack.add(operatorStack.pop());
}
/*
程序运行到此处
说明栈顶优先级低于当前优先级
或者说符号栈为空
这个时候直接压栈
*/
operatorStack.push(s);
}
}
/*
程序运行到此处
说明第1轮扫描完毕
这时需要将符号栈剩余的操作符
加入结果集当中
*/
while (operatorStack.size() != 0){
resultStack.add(operatorStack.pop());
}
/*
程序运行到此处
说明已经处理好了
直接返回结果
*/
return resultStack;
}
/**
* 字符串表达式转ArrayList集合
* @param string 字符串表达式
* @return ArrayList集合
*/
public static List<String> stringExpressionToArrayList(String string){ // 1+((2+3)*4)-5
/*
初始化数据
*/
List<String> stringList = new ArrayList<>(); // 定义结果集
String str; // 多位数拼接
int index = 0; // 遍历字符串
char c; // 遍历到的字符
do {
if ((c = string.charAt(index)) < 48 || (c = string.charAt(index)) > 57){
/*
程序运行到此处
说明c不是一个数字
直接加入stringList集合就行
*/
stringList.add("" + c);
index++;
}else{
/*
程序运行到此处
说明c是一个数字
这个时候需要考虑多位数
并且需要判断后一位是否
已经走到了表达式最后
*/
str = "";
while (index < string.length() && (c = string.charAt(index)) >= 48 && (c = string.charAt(index)) <= 57){
/*
程序运行到此处
说明是多位数
需要进行拼接
*/
str += c;
index++;
}
/*
程序运行到此处
说明拼接完毕
或者说本来就是1位数
直接加进去就行
*/
stringList.add(str);
}
}while (index < string.length());
/*
程序运行到此处
说明扫描完毕
直接返回集合即可
*/
return stringList;
}
}
/**
class OperatorPrecedence
return precedence of operator
@author 404 little dinosaur
*/
class OperatorPrecedence{
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
public static int getPriorityNumber(String operation){
int result = 0;
switch (operation){
case "+":
result = ADD;
break;
case "-":
result = SUB;
break;
case "*":
result = MUL;
break;
case "/":
result = DIV;
break;
default:
break;
}
return result;
}
}
/*
code structure
d19
main
convertInfixExpressionToPostfixExpression
stringExpressionToArrayList
OperatorPrecedence
getPriorityNumber
ADD
SUB
MUL
DIV
*/
本文详细介绍了将中缀表达式转换为后缀表达式的思路和方法,包括关键的辅助过程和完整的Java实现代码。通过理解这个转换过程,可以深入掌握数据结构与算法中的操作技巧。
4245

被折叠的 条评论
为什么被折叠?



