一、中缀表达式转换成后缀表达式
具体步骤如下:
1、初始化栈stack(暂时存放运算符)以及集合list(存放后缀表达式)
2、从左向右扫描中缀表达式
3、当前元素为数字时,直接添加到list中
4、当前元素为运算符时,需要比较当前运算符与stack中栈顶运算符的优先级
4.1、若stack为空,或者栈顶运算符为 '(' 时,当前运算符直接入栈
4.2、stack不为空,当前运算符优先级高于栈顶运算符时,则将当前运算符直接入栈;
当前运算符优先级小于等于栈顶运算符时,则将栈顶运算符出栈添加到list中, 并重复4.1-4.2,将当前运算符继续与新的栈顶运算符比较。
5、当前元素为 '(' 时,直接压入stack中
6、当前元素为 ')' 时,循环stack,一次弹出stack栈顶运算符并添加到list中,直到遇到 '(' 为止,此时将栈顶运算符为 '(' 时直接出 栈,继续扫描下一元素
7、重复步骤 2 至 6,直到中缀表达式被扫描完
8、将stack栈中剩余的运算符依次弹出并添加到list中,最后得到后缀表达式
例1:中缀表达式:60 + 8 / 2
扫描到的元素 | stack(栈底->栈顶) | list | 说明 |
60 | 空 | 60 | 数字,直接添加到list |
+ | + | 60 | 栈空,运算符直接入栈 |
8 | + | 60,8 | 数字,直接添加到list |
/ | +,/ | 60,8 | / 优先级比 + 高,直接入栈 |
2 | +,/ | 60,8,2 | 数字,直接添加到list |
扫描结束 | + | 60,8,2,/ | 弹出栈顶运算符 |
扫描结束 | 空 | 60,8,2,/,+ | 弹出栈顶运算符 |
例2:中缀表达式 1+((2+3)*4)-6/2
扫描到的元素 | stack(栈底->栈顶) | list | 说明 |
1 | 空 | 1 | 数字,直接添加到list |
+ | + | 1 | 栈空,运算符直接入栈 |
( | +,( | 1 | 左括号,直接入栈 |
( | +,(,( | 1 | 左括号,直接入栈 |
2 | +,(,( | 1,2 | 数字,直接添加到list |
+ | +,(,(,+ | 1,2 | 栈顶为 ( 时,运算符直接入栈 |
3 | +,(,(,+ | 1,2,3 | 数字,直接添加到list |
) | +,(, | 1,2,3,+ |
),(1)栈中运算符依次弹出添加到list,直到遇到左括号为止,(2)将栈中左括号弹出 |
* | +,(,* | 1,2,3,+ | 栈顶元素为 ( 时,运算符直接入栈 |
4 | +,(,* | 1,2,3,+,4 | 数字,直接添加到list |
) | + | 1,2,3,+,4,* | ),(1)栈中运算符依次弹出添加到list,直到遇到左括号为止,(2)将栈中 ( 弹出 |
- | - | 1,2,3,+,4,*,+ | - 与 + 两运算符优先级相等,(1)弹出栈顶运算符+并添加到list,(2) - 入栈 |
6 | - | 1,2,3,+,4,*,+,6 | 数字,直接添加到list |
/ | -,/ | 1,2,3,+,4,*,+,6 | / 优先级高于 -,将 / 入栈 |
2 | -,/ | 1,2,3,+,4,*,+,6,2 | 数字,直接添加到list |
扫描结束 | 空 | 1,2,3,+,4,*,+,6,2,/,- | 将栈中剩余运算符依次弹出添加到list |
代码实现:
//1 先将表达式转换成list
public static List<String> expressionToList(String expression){
int i = 0;//下标,用于扫描表达式
char ch;//用于接收扫描字符
String numStr;//用于拼接多位数
ArrayList<String> list = new ArrayList<String>();//存放表达式
do {
//需要判断ch是操作符还是数字,此处不理解的可以百度ACSII码
if((ch = expression.charAt(i)) < 48 || (ch = expression.charAt(i)) > 57) {
list.add(""+ch);
i++;
}else {//如果是数字,则需要判断是否是多位数
numStr = "";
while(i < expression.length() && (ch = expression.charAt(i)) >= 48 && (ch = expression.charAt(i)) <= 57) {
numStr+=ch;
i++;
}
list.add(numStr);
}
}while(i < expression.length());
return list;
}
//2 将中缀表达式转为后缀表达式
public static List<String> parseSuffixExpressionList(List<String> list){
Stack<String> stack = new Stack<String>();
ArrayList<String> resList = new ArrayList<String>();
//循环中缀表达式
for(String item : list) {
//是多位数时直接入栈
if(item.matches("\\d+")) {
resList.add(item);
//运算符时需要判断入栈
}else if(item.equals("(")) {
stack.push(item);
}else if(item.equals(")")) {
while(true) {
if(stack.peek().equals("(")) {
break;
}
resList.add(stack.pop());
}
//此时需要将)弹出
stack.pop();
}else {
//(当前运算符优先级小于等于栈顶运算符)直接将栈顶元素出栈放入list
while(stack.size()!=0 && priority(item) <= priority(stack.peek())) {
resList.add(stack.pop());
}
//还需要将item压入栈中
stack.push(item);
}
}
//将栈中剩余运算符弹出放入到resList
while(stack.size()!=0) {
resList.add(stack.pop());
}
return resList;
}
//数字越大,则优先级就越高
public int priority(String oper) {
int result = 0;
if(oper.equals("*") || oper.equals("/")) {
return 2;
}else if(oper.equals("+") || oper.equals("-")){
return 1;
}else {
// System.out.println("不存在此运算符");
return result;
}
}
二、后缀表达式计算(不包含小数情况)
具体步骤如下:
1、初始化栈stack,并将后缀表达式从左向右扫描
2、当前元素为数字时,直接入栈
3、当前元素为运算符时,依次弹出栈中两个数字,并进行运算,得到结果后入栈
4、重复1-3
直接上例子:(5+4)*3-7 对应的后缀表达式为 5 4 + 3 * 7 -
1、从左向右扫描,将 5 和 4 入栈
2、遇到运算符 +,依次弹出栈中 4 和 5(4为栈顶元素,5为次顶元素),计算出 4 + 5 = 9,将 9 入栈
3、将数字 3 入栈。
4、遇到运算符 *,依次弹出栈中 3 和 7,计算出 3 * 9 = 27,将 27 入栈
5、将数字 7 入栈。
6、遇到运算符 -,依次弹出栈中 27 和 7,计算出 27 - 7 = 20,此时已扫描结束,最终结果为 20
//1 首先将表达式转换成list
public List<String> expressionToList(String expression){
int i = 0;//下标,用于扫描表达式
char ch;//用于接收扫描字符
String numStr;//用于拼接多位数
ArrayList<String> list = new ArrayList<String>();//存放表达式
do {
//需要判断ch是操作符还是数字,此处不理解的可以百度ACSII码
if((ch = expression.charAt(i)) < 48 || (ch = expression.charAt(i)) > 57) {
list.add(""+ch);
i++;
}else {//如果是数字,则需要判断是否是多位数
numStr = "";
while(i < expression.length() && (ch = expression.charAt(i)) >= 48 && (ch = expression.charAt(i)) <= 57) {
numStr+=ch;
i++;
}
list.add(numStr);
}
}while(i < expression.length());//扫描结束
return list;
}
//2 运算方法
public void calculate(List<String> expressionList) {
//新建一个stack
Stack<String> stack = new Stack<String>();
int num1;//操作数
int num2;
int res;//运算结果
//开始扫描
for (String item : expressionList) {
if(item.matches("\\d+")) {// \d+表示1个或多个0到9的数字,是整数部分(至少是一位整数的整数部分)
//直接入栈
stack.push(item);
}else {
//操作符,弹出两位数进行运算,运算结果重新进栈
num2 = Integer.parseInt(stack.pop());
num1 = Integer.parseInt(stack.pop());
res = 0;
//后缀表达式(逆波兰表达式)是从左向右扫描
if(item.equals("+")) {
res = num1 + num2;
}else if(item.equals("-")) {
res = num1 - num2;
}else if(item.equals("*")) {
res = num1 * num2;
}else if(item.equals("/")) {
res = num1 / num2;
}else {
throw new RuntimeException("运算符错误");
}
stack.push(res+"");
}
}
//循环结束后只剩下运算结果
System.out.println("运算结果="+stack.pop());
}