利用栈实现中缀表达式和后缀表达式互转
中缀表达式转后缀表达式
一、原理概述:
a.定义一个栈用于存放运算符,以及 括号 “[()]” 操作符
b.定义一个字符串result用于接收计算结果
c.从表达式第一个字符开始作为判断位;( 判断位,用于与栈顶元素对比优先级,从而确定:将判断位入栈 或者 将栈顶元素弹出 )
d.遇到操作数作为判断位,直接将其作为结果添加到result的末尾;
e.如果碰到判断位是操作符,当栈为空时直接将其入栈,表达式下一位作为判断位;栈不为空时,比较判断位与栈顶的元素的优先级;
f.如果 判断位的优先级 >= 栈顶元素的优先级,判断位入栈成为新栈顶,表达式下一位成为判断位;
g.如果 判断位的优先级 < 栈顶元素的优先级,弹出栈顶元素(运算符打印到结果,括号忽略),栈顶元素更新,判断位不变,继续对比新的栈顶与判断位,,,,直至结束;
需要注意的是:
- 针对左括号 ( 和 [ ,他们的优先级不是固定的;
- 当他们作为判断位与栈顶元素对比时,他们是最高的;
- 当他们作为栈顶元素与判断位对比时,他们的优先级是最低的;
作为判断位时:
- 判断它是否入栈的优先级:
作为栈顶元素:
PS*考验视力的时候了,,,,
二、案例以及具体栈操作:
-
定义栈:X = {} ,从右到左表示栈底到栈顶
-
定义打印结果:result = “”;
-
定义表达式:F = a + c * [ b * (c + d) + g ]
1.a是操作数,输出,打印到输出结果;
X = {} result = "a"; F = a + c * [ b * (c + d) + g ]
2.“+” 是操作符,入栈;
X = {+} result = "a"; F = a + c * [ b * (c + d) + g ]
3.c 是操作数,输出;
X = {+} result = "ac"; F = a + c * [ b * (c + d) + g ]
4.“*”是操作符,优先级大于等于当前栈顶“+”,“*” 入栈;
X = {+,*} result = "ac"; F = a + c * [ b * (c + d) + g ]
5."[" 特殊符号,《判断入栈时视为最高优先级,判断出栈时视为最低优先级》,此时判断它是否需要入栈,此时优先级最高,大于等于当前栈顶"*",所以入栈;
X = {+,*,[} result = "ac"; F = a + c * [ b * (c + d) + g ]
6.b为操作数,输出;
X = {+,*,[} result = "acb"; F = a + c * [ b * (c + d) + g ]
7.”*“ 操作符,此时栈顶为 ”[“ ,需要根据优先级判断是否需要将当前栈顶出栈,那么 ”[“ 优先级最低,”*“ 高于栈顶的 ”[“ 《特殊符号入栈》;
X = {+,*,[,*} result = "acb"; F = a + c * [ b * (c + d) + g ]
8.”(“ 入栈 《特殊符号,它作为入栈判断位,视为次高优先级,当它是栈顶元素时,视为次低优先级》,此时它需要入栈;
X = {+,*,[,*,(} result = "acb"; F = a + c * [ b * (c + d) + g ]
9.操作数 c 输出到result ;
X = {+,*,[,*,(} result = "acbc"; F = a + c * [ b * (c + d) + g ]
10."+" 操作符,此时 ”(“ 作为栈顶,优先级小于 ”+“ 那么 “+” 入栈;
X = {+,*,[,*,(,+} result = "acbc"; F = a + c * [ b * (c + d) + g ]
11.操作数d ,输出;
X = {+,*,[,*,(,+} result = "acbcd"; F = a + c * [ b * (c + d) + g ]
12.")" 操作符,优先级低于任意运算符 《 + - * / 》, 等于与它配对的 “(” 那么此时,它小于当前栈顶 “+”,当前栈顶出栈,并输出;
X = {+,*,[,*,(} result = "acbcd+"; F = a + c * [ b * (c + d) + g ]
13.当前栈顶变为:“(” 优先级等于“)” 括号不需要打印到输出结果,所以直接出栈,当前判断位 “)” 也舍弃;
X = {+,*,[,*} result = "acbcd+"; F = a + c * [ b * (c + d) + g ]
14.新的判断位,变成“+” 它的优先级小于当前栈顶 “*” ,所以当前栈顶运算符,出栈并输出;
X = {+,*,[} result = "acbcd+*"; F = a + c * [ b * (c + d) + g ]
15.新栈顶:“[” ,作为栈顶时,它优先级最低,等于与他配对的 “]” , 当前判断位 “+” 优先级大于栈顶的 “[” 所以需要入栈;
X = {+,*,[,+} result = "acbcd+*"; F = a + c * [ b * (c + d) + g ]
16.”+“ 入栈后下一个判断位是操作数 g,直接输出;
X = {+,*,[,+} result = "acbcd+*g"; F = a + c * [ b * (c + d) + g ]
17.g 输出后,新判断位 ”]“ , 它的优先级小栈顶”+“ 所以栈顶”+“ 出栈并输出;
X = {+,*,[} result = "acbcd+*g+"; F = a + c * [ b * (c + d) + g ]
18.新栈顶”[“ 优先级等于判断位”]“ 且他们配对,由于括号不用打印到输出结果,所以同时舍弃;
当F 表达式走到结尾,且栈内还有操作符时,那么需要将栈中所有的运算符按序出栈,并输出到结果:" 括号只出栈,不输出到结果 ";
最终得到后缀表达式:
X = {} result = "acbcd+*g+*+";
- 大致逻辑如上,上面的逻辑是没有问题的,按照所述逻辑去实现代码应该问题不大;
三、代码以及实现:
import java.util.Stack;
public class InfixToSuffix {
public static void main(String[] args){
String formula = "a+b+[c*(d-f)+g]*h";
//formula = "a+b*(c+d+e)+g*h";
//formula = "a+c*[b*(c-d)+g]";
//formula = "b*(c+d+e)";
System.out.println(infixToSuffix(formula.toCharArray()));
}
public static String infixToSuffix(char[] formula){
StringBuilder result = new StringBuilder();
Stack<Character> formulaStack = new Stack<>();
boolean isPush = true;// 标记上一次循环,栈的操作是入栈还是出栈
boolean isEnd = false;// 表达式最后一位是否已经处理完成
int index = 0;// 标记当前判断位的位置
int current;// 当前判断位优先级
int top ; // 栈顶元素优先级
while(index < formula.length){
current = formateChar(formula[index]);
if (!formulaStack.isEmpty()) top = formateChar(formulaStack.peek()); else top = 0;
if (index == formula.length - 1){// 表达式已经判断完成,栈中所有操作符出栈并输出到结果
if (current < 0 && !isEnd) { //表达式最后一位为操作数
result.append(formula[index]);
isEnd = true;
}
if (!formulaStack.isEmpty()){ //将栈中非括号操作符出栈并输出
char end = formulaStack.pop();
if("[(".indexOf(end) < 0)
result.append(end);
} else { // 栈空,退出
index ++;
}
} else {
if ((top - current == 90 || top - current == 100)){// 左括号与右括号匹配,同时舍弃
index++;
formulaStack.pop();
} else if (current < 0){//数字直接输出到结果
result.append(formula[index]);
index++;
} else if (!formulaStack.isEmpty() && current > 0) {
//判断位不是数字,栈不空,那么对比栈顶元素与当前判断位的优先级
if (current > top){栈顶优先级小于当前判断字符
formulaStack.push(formula[index]); //top = current;
index ++;
isPush = true;
} else if (top > current){//栈顶优先级大于当前判断字符
if (top > 90){ // 出栈时关于括号的优先级反转:最高->最低 次高 -> 次低
formulaStack.push(formula[index]); //top = current;
index ++;
isPush = true;
} else {
result.append(formulaStack.pop()); //top = formulaStack.peek();//栈顶元素出栈
isPush = false;
}
}else if (current == top){//栈顶元素优先级等于当前判断位字符的优先级
if (isPush){ // 上次循环栈的操作是入栈,那么优先级相等入栈
formulaStack.push(formula[index]);//top = current;
index ++;
} else {// 上次循环栈的操纵是出栈,此时优先级相等也出栈
result.append(formulaStack.pop()); //top = formulaStack.peek();//栈顶元素出栈
}
}
} else if (formulaStack.isEmpty() && current > 0){ // 栈空,且当前判断位是操作符,那么直接入栈
formulaStack.push(formula[index]);
index ++;
}
}
}
return result.toString();
}
public static int formateChar(char a){//设置优先级(是否进栈)
if ("[".indexOf(a) >= 0) return 101; //出栈优先级最低 101 - 1 = 100 [和] 配对
else if ("(".indexOf(a) >= 0) return 92; //出栈优先级次低 92 - 2 = 90 (和) 配对
else if ("*/".indexOf(a) >= 0) return 4;
else if ("-+".indexOf(a) >= 0) return 3;
else if (")".indexOf(a) >= 0) return 2;
else if ("]".indexOf(a) >= 0) return 1;
else if (" ".indexOf(a) >= 0) return 0; //栈空时栈顶的优先级
else return -1; //操作数优先级最低
}
}
后缀表达式转中缀表达式:
一、原理概述:
- a.从后缀表达式第一个元素开始,遇到操作数(数字),即压入栈中;
- b.遇到操作符则弹出当前栈最顶上的两个数字进行运算,并将结果压入栈中;
- c.按照上述规律直至后缀表达式遍历完成,最后栈中只剩下一个表达式即为计算结果;
由于操作简单就不再赘述了。
二、代码实现
public static String suffixToInfix(char[] suffixs){
String TEMP = "";
Stack<String> suffixStack = new Stack<>();
int lastAdd = 0;
int index = 0;
int current;
while (index < suffixs.length){
current = formateChar(suffixs[index]);
if (current < 0){ // 数字直接入栈
suffixStack.push("" + suffixs[index]);
index++;
} else if (current == 3){ // + 或 - 操作符,
TEMP = suffixs[index] + suffixStack.pop();
TEMP = suffixStack.pop() + TEMP;
index++;
suffixStack.push(TEMP);
lastAdd = 1;
} else if (current == 4){ // * 或 / 运算符
if (lastAdd != -1){ // 上一步运算不是乘法,需要用括号,保证优先级
TEMP = suffixs[index] + "(" + suffixStack.pop() + ")";
TEMP = suffixStack.pop() + TEMP;
} else { // 上一步计算也是乘法,优先级可以得到保证
TEMP = suffixs[index] + suffixStack.pop();
TEMP = suffixStack.pop() + TEMP;
}
index++;
suffixStack.push(TEMP);
lastAdd = -1;
}
}
return suffixStack.pop();
}
public static int formateChar(String a){
if ("*/".indexOf(a) >= 0) return 4;
else if ("-+".indexOf(a) >= 0) return 3;
else if (" ".indexOf(a) >= 0) return 0;
else return -1;//字母 或表达式
}