自打遇到栈,一直都想些写一篇通俗易懂的将中缀表达式转化为后缀表达式的博文,今天总算完成了这个心愿。
所有的解释在代码行里面均有解释。有什么不懂的可以在评论区或者私信我。
为了不用一直拉动代码行看注释(这回很麻烦也很浪费时间),本人将较长的注释分成了两行。
写在前面:
后缀表达式:波兰逆序数,将中缀表达式转换成后缀表达式不用做算数运算,它不求中缀表达式的值,只是把操作数和操作符重新排列成另一种形式:后缀表示法。然后再求后缀表达式的结果。在解析表达式的时候,我们是将运算操作符存放在一个栈里,*/的优先级要比+-高,但是如果+或者-在括号里面,那么它的优先级就要比* /要高。
定义栈代码:
(对栈还不够了解的,可以看我的另一篇博文)
https://blog.csdn.net/szlg510027010/article/details/82696158
转换代码:
/**
* 将中缀表达式转化为后缀表达式
* @author Administrator
*
*/
public class InToPost {
private String input;
private String output="";
private StackX theStack;
public InToPost(String in) {
input = in;
int stackSize = input.length();
theStack = new StackX(stackSize);
}
public String doTrans() {
//利用for循环,读取中缀表达式中的每一个字符
for(int i=0;i<input.length();i++) {
//定义一个字符型变量ch,将中缀表达式的字符赋给ch
char ch = input.charAt(i);
//演绎字符ch是否入栈,将栈中的内容先打印出来
theStack.diaplayStack("For "+ch+" ");
//利用switch-case语句,对应字符对应不同的操作
switch(ch) {
case '(':
//如果ch是'('的话,直接将该字符压入栈中
theStack.push(ch);
break;
//如果ch是')'的话,执行gotParen操作,Paren是parenthesis的缩写,
//表示括号的意思,这里即要实现获取')'括号相对应的操作
case ')':
gotParen(ch);
break;
//如果ch是'+'或者'-'的话,获取操作Oper是Operation的缩写,即操作的意思
case '+':
case '-':
gotOper(ch,1);
break;
//如果ch是'*'或者'/',执行gotOper方法
case '*':
case '/':
gotOper(ch,2);
break;
//如果获取的字符既不是+-*/,也不是'('或者')',表示这个字符是数字,直接赋值给output.
default:
output+=ch;
break;
}
}
//当执行玩上述操作以后,栈不为空,则将栈中的元素一一赋值给output
//什么时候执行完上述操作栈依然不为空呢?有很多例子,比如说(A+B)*C
//在(A+B)*C中最后的时候栈中还会有*这个符号,因为我们在ch在==')'的时候
//就把栈中里面的内容'+'和'('[注意这里是有顺序的,先执行'+']给执行了,在遇到'('的时候
//直接pop,其实质是将top--,'('它本身还在数组里头,这在我们初步学习栈的时候就已经说明过了
//此时top==-1.相当于栈是空的
//遇到'*'以后,将其压入栈中
//因为'*'后面已经没有其它操作符[+-*/)(],所以'*'就一直保存在栈中了
while(!theStack.isEmpty()) {
theStack.diaplayStack("While ");
output+=theStack.pop();
}
theStack.diaplayStack("End ");
//返回output,此时已经完成了将中缀表达式转化为后缀表达式
return output;
}
//当遇到'(''+''-'或者'*'/'的时候执行以下操作
public void gotOper(char opThis,int prec1) {
//只要栈中不为空,就要将栈顶元素拿出来,
//若是'('则放回,若是'+''-''*''/'就要和栈顶元素进行比较
while(!theStack.isEmpty()) {
//获取栈顶元素
char opTop = theStack.pop();
//如果栈顶元素是'(',则将其放回栈中,因为有'(',
//表示后面一定有运算操作是要先执行的,'('也可以是看做一个标志符,或者说是分割符
if(opTop=='(') {
theStack.push(opTop);
//退出循环,继续下一个字符的操作
break;
}//否则如果不是'('的话,执行下面操作
else {
//定义一个prec2,prec2代表的是栈顶元素,
//目的是为了跟prec1进行比较,prec1表示的是要插入栈中元素
//如果prec2>prec1的话表示栈顶元素的优先级比要插入栈中的元素优先级要大,
//此时我们就应该将栈顶元素赋值给output,比如栈顶元素opTop为'*' opThis为'+'
//如果prec2<prec1的话,表明栈顶元素的优先级要小于要插入栈中的优先级,
//此时我们将opTop放回栈中,比如栈顶元素opTop为'+' opThis为'*',刚好与上述情况相反
int prec2;
if(opTop=='+' || opTop=='-') {
prec2 = 1;
}else
prec2 = 2;
if(prec2<prec1) {
//如果栈顶元素的优先级要小于要插入栈中的优先级,此时我们将opTop放回栈中
theStack.push(opTop);
//退出循环,继续下一个字符的操作
break;
}else
//如果栈顶元素的优先级要大,则将其赋值给output
output += opTop;
}
}
//总结一下上述的操作,其实就是将栈顶元素取出来,然后考虑它是否应该放回到栈中,
//放回栈中有两种情况:
//1、如果遇到'(',我们就将它放回栈中
//2、如果栈顶元素opTop的优先级要比opThis的优先级药效,我们将它(栈顶元素opTop)放回栈中
//赋值给output的情况只有一种:
//就是栈顶元素opTop的优先级要比opThis的要大,
//此时我们直接将其赋值给output,
//因为优先级都比opThis要大了,我们当然要先执行该运算啊!
//考虑完栈顶元素opTop是应该放回还是不放回以后,我们将opThis放到栈里面去
theStack.push(opThis);
//注:此方法针对的符号是
//'(' '+' '-' '*' '/',五个,
//如果遇到的是')',不执行该方法,执行的是下面的方法gotOparen
}
//如果遇到')'我们并不将')'压入栈中,这时候考虑的是是否将栈中元素赋值给output的问题了
public void gotParen(char ch) {
//如果该栈不为空,为空的时候不可能(只要不是故意的)出现')',
//因为在表达式里面有')'理所当然就有'('
//所以不应该为空,为空根本就么有意义去讨论
while(!theStack.isEmpty()) {
//获取栈顶元素,只要栈顶元素不是'(',
//则我们将其赋值给output,然后进行下一次操作,直到遇到'('为止
char chx = theStack.pop();
if(chx=='(') {
break;
}else {
output += chx;
}
}
}
}
测试代码:
/**
* 测试转换
* @author Administrator
*
*/
public class TestTrans {
public static void main(String[] args) {
int interAns = 0;
String input = "3*(4+5)-6/(1+2)";
System.out.println("前缀表达式:"+input);
InToPost test = new InToPost(input);
String output = test.doTrans();
System.out.println("后缀表达式:"+output);
System.out.println("计算后缀表达式:--------");
//定义一个新的栈,用于存放数字
Stack2 newStack = new Stack2(output.length());
//遍历output即后缀表达式,如果遇到数字则将其入栈
//如果遇到的是操作符,则将紧挨操作符的前两个数字进行运算
for(int i=0;i<output.length();i++) {
//获取output中小标对应的字符
char ch = output.charAt(i);
//如果获取的元素是数字,那么将其用过相减转化为int类型
//然后将其放到入栈
if(ch>='0'&&ch<='9') {
int number=ch-'0';
newStack.push(number);
System.out.println(newStack.peekTop());
}else {
//获取符号前面的两个数字
//在这里一定要注意
//num1和num2的顺序,+、*无所谓,但是-、/有所谓
int num2 = newStack.pop();
int num1 = newStack.pop();
switch(ch) {
case '+':
interAns = num1 + num2;
break;
case '-':
interAns = num1 - num2;
break;
case '*':
interAns = num1 * num2;
break;
case '/':
interAns = num1 / num2;
break;
}
//讲运算的结果入栈,然后遍历下一个元素
newStack.push(interAns);
}
}
//打印结果
System.out.println("The Answer is:"+interAns);
}
}
测试结果:
前缀表达式:D*(A+B)*C
For D Stack (bottom-->top):
For * Stack (bottom-->top):
For ( Stack (bottom-->top):*
For A Stack (bottom-->top):* (
For + Stack (bottom-->top):* (
For B Stack (bottom-->top):* ( +
For ) Stack (bottom-->top):* ( +
For * Stack (bottom-->top):*
For C Stack (bottom-->top):*
While Stack (bottom-->top):*
End Stack (bottom-->top):
后缀表达式:DAB+*C*
计算结果:
前缀表达式:3*(4+5)-6/(1+2)
后缀表达式:345+*612+/-
计算后缀表达式:--------
3
4
5
6
1
2
The Answer is:25