问题描述:将算术表达式由中序表达式转为后序表达式(目前仅限加减乘除)
题目的核心还是利用Stack栈的特点——后进先出,解决问题,注意出栈规则——按照算术运算的优先级。
中序表达式:方便人读取的算术表达式,如:1+2-2/(3-8) ,类似这样的就是中序表达式了,其实就是我们日常中经常看到的算术表达式。
后序表达式:方便计算机读取的算术表达式,如:12+238-/- ,这个后序表达式就是上面的中序表达式的运算顺序了。
程序的算法流程分析:
1、准备两个栈,分别存储中序字符串中的 数字-->数字栈numsstack,符号-->符号栈opertstack,最终后序表达式结果存入——数字栈;
2、从中序表达式中一个一个循环读取字符-->c,并对字符进行判定,取出的字符c,大致分四种情况:
1)、c为数字(0-9)时,直接进入——数字栈numsstack;
2)、c为符号-->运算符(+,-,*,/)时,要视以下几种情况,进行弹栈、压栈操作:
a、如果符号栈opertstack此时为空,直接将c压入符号栈opertstack;
b、如果符号栈opertstack不为空,弹出栈顶元素存入temp中:
i、如果temp为乘或者除(*或者/),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
ii、如果temp为加或者减(+或者-),此时要看c中的符号优先级:
*、如果c为加或者减(+或者-),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
**、如果c为乘或者除(*或者/),要看c在中序表达式中的前(pre)和后(next),是否分别为右括号(')'),和左括号('('):
@、是的话,temp和c都要压入符号栈opertstack;
@@、不是的话,c的优先级要高于temp,c压入数字栈numsstack,temp压入符号栈opertstack;
iii、如果temp为左括号(‘(’),将temp和c都压入符号栈opertstack中,等待右括号的到来;
3)、c为符号-->右括号(‘)’)时,符号栈opertstack弹栈,并将弹出的栈顶元素加入数字栈numsstack,直至弹出的栈顶为(‘(’)左括号时,结束弹栈操作;
4)、c为符号-->左括号(‘(’)时,将c直接压入符号栈opertstack中;
3、中序表达式遍历结束后,如果符号栈opertstack里还有对象,就挨个出栈,压入数字栈numsstack。
说实话,问题比我想象的要复杂,折腾了一天,终于整完了。测试了几组数据,目前看没啥大问题。
具体的实现都在程序中了。
import java.util.Stack;
//将算术表达式由中序表达式转为后序表达式
/*
* 题目的核心还是利用Stack栈的特点——后进先出,解决问题。
* 中序表达式:方便人读取的算术表达式,如:1+2-2/(3-8) ,类似这样的就是中序表达式了,其实就是我们日常中经常看到的算术表达式。
* 后序表达式:方便计算机读取的算术表达式,如:12+238-/- ,这个后序表达式就是上面的中序表达式的运算顺序了。
*/
/*
* 程序的算法流程分析:
* 1、准备两个栈,分别存储中序字符串中的 数字-->数字栈numsstack,符号-->符号栈opertstack,最终后序表达式结果存入——数字栈;
* 2、从中序表达式中一个一个循环读取字符-->c,并对字符进行判定,取出的字符c,大致分四种情况:
* 1)、c为数字(0-9)时,直接进入——数字栈numsstack;
* 2)、c为符号-->运算符(+,-,*,/)时,要视以下几种情况,进行弹栈、压栈操作:
* a、如果符号栈opertstack此时为空,直接将c压入符号栈opertstack;
* b、如果符号栈opertstack不为空,弹出栈顶元素存入temp中:
* i、如果temp为乘或者除(*或者/),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
* ii、如果temp为加或者减(+或者-),此时要看c中的符号优先级:
* *、如果c为加或者减(+或者-),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
* **、如果c为乘或者除(*或者/),要看c在中序表达式中的前(pre)和后(next),是否分别为右括号(')'),和左括号('('):
* @、是的话,temp和c都要压入符号栈opertstack;
* @@、不是的话,c的优先级要高于temp,c压入数字栈numsstack,temp压入符号栈opertstack;
* iii、如果temp为左括号(‘(’),将temp和c都压入符号栈opertstack中,等待右括号的到来;
* 3)、c为符号-->右括号(‘)’)时,符号栈opertstack弹栈,并将弹出的栈顶元素加入数字栈numsstack,直至弹出的栈顶为(‘(’)左括号时,结束弹栈操作;
* 4)、c为符号-->左括号(‘(’)时,将c直接压入符号栈opertstack中;
*3、中序表达式遍历结束后,如果符号栈opertstack里还有对象,就挨个出栈,压入数字栈numsstack。
*/
public class MidExpressTransLastExpress {
//两个栈分别存储中序表达式中的数字和符号
//numsstack-->存储数字的栈,也是最终的后序表达式的结果栈。
//opertstack-->存储运算符等符号的栈。
private static Stack<Character> numsstack=new Stack<Character>();
private static Stack<Character> opertstack=new Stack<Character>();
//具体的转换方法
public static void transMidToLast(String str) {
//存储最终的后序表达式的字符串
String target=new String();
//中序字符串中,当前位置--->i 位置的字符c
char c;
// i位置的前一个字符
char next=0;
// i位置的后一个字符
char pre=0;
//比较用的临时字符存储空间
char temp = 0;
//程序的主要交换逻辑,一个for循环,将中序表达式从头到尾遍历一遍。
for(int i=0; i<str.length(); i++) {
c=str.charAt(i);
if(i<str.length()-1) next=str.charAt(i+1);
if(i>0) pre=str.charAt(i-1);
//根据获取的当前位置 i ,来进行分支选择。
switch(c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
numsstack.push(c);//c为数字时,进入数字栈
break;
// c为加减乘除时,进行的选择操作
case '+':
case '-':
case '*':
case '/':
if(opertstack.isEmpty()) opertstack.push(c);//符号栈为空的话,符号c直接进栈。
else temp=opertstack.pop();//否则弹出符号栈的栈顶元素,存入临时空间temp中。
if(temp=='*' || temp=='/') {//符号栈的栈顶为乘除时,直接将这个栈顶元素压入数字栈,当前符号压入符号栈。
numsstack.push(temp);
opertstack.push(c);
}
if(temp=='+' || temp=='-' ) {//符号栈栈顶为加减时,要分两个情况,一个是c为乘除,一个是c为加减。
if(c=='*' || c=='/') {//c 为乘除时,要看当前c在中序表达式中的前(next)后(pre),是否为左括号和右括号,两种情况。
if(next=='(' || pre==')') {//c的前后为左右括号时,要将temp和c,按顺序压入字符栈。
opertstack.push(temp);
opertstack.push(c);
}else {//c的前后不是左右括号时,temp如字符栈,c入数字栈。
opertstack.push(temp);
numsstack.push(c);
}
}
if(c=='+' || c=='-') {//c为加减时,temp如数字栈,c如字符栈。
numsstack.push(temp);
opertstack.push(c);
}
}
if(temp=='(') {//符号栈的栈顶元素为左括号时,符号栈重新压入取出的栈顶,然后再压入c。
opertstack.push(temp);
opertstack.push(c);
}
break;
case ')'://c为右括号时,字符栈的栈顶要出栈,同时压入数字栈,直到字符栈出栈的栈顶元素为左括号为止。
temp=opertstack.pop();
while(temp!='(' && !opertstack.isEmpty()) {
numsstack.push(temp);
temp=opertstack.pop();
}
temp=0;
break;
case '('://c为左括号,无条件直接压入字符栈。
opertstack.push(c);
break;
default:
break;
}
}
//中序表达式,遍历结束后,如果字符栈里还有符号,直接出栈,压入数字栈中。
while(!opertstack.isEmpty()) {
temp=opertstack.pop();
if(temp!='(') numsstack.push(temp);
}
System.out.println(numsstack.toString());
//数字栈开始出栈,一个一个加入target字符串中。
while(!numsstack.isEmpty()) {
target=numsstack.pop().toString()+target;
}
System.out.println(target);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
transMidToLast("(1-2)*4+(91+2)");
transMidToLast("(5+1)*2-3*(2*(1-3))");
transMidToLast("(5+1)*2-2*((1-3)*2)/2");
}
}