前缀、中缀、后缀表达式的定义
前缀表达式、中缀表达式、后缀表达式是四则运算的三种不同的表达方式。
中缀表达式就是我们常使用的运算表达式,例如:(1+2)*3/(4+5)
前缀表达式又被称为波兰式,它的特点是运算符位于操作数的前面。例如上面的表达式用前缀表达式表示的结果为:
后缀表达式又被称为逆波兰式,它的特点是运算符位于操作数的后面。例如上面的表达式用后缀表达式表示的结果为:
中缀表达式转为前缀表达式
转换的步骤为:
1.初始化两个栈:运算符栈s1,储存中间结果的栈s2
2.从右至左扫描中缀表达式
3.遇到操作数时,将其压入s2
4.遇到运算符时,比较其与s1栈顶运算符的优先级
1.如果s1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈
2.否则,若优先级比栈顶运算符的较高或相等,也将运算符压入s1
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较
5.遇到括号时
1.如果是右括号“)”,则直接压入s1
2.如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃
6.重复步骤2至5,直到表达式的最左边
7.将s1中剩余的运算符依次弹出并压入s2
8.依次弹出s2中的元素并输出,结果即为中缀表达式对应的前缀表达式
代码实现如下(有很多可以重构的地方,以后有时间再回来重构):
package top.zhanglugao.expression;
import top.zhanglugao.stack.LinkedStack;
public class ExpressionTransform {
public static void main(String[] args) {
//(1+2)*3/(4+5)
Character[] item=new Character[]{'(','1','+','2',')','*','3','/','(','4','+','5',')'};
Character[] characters = transformMiddleEx2PreEx(item);
for(Character c:characters){
if(c!=null)
System.out.println(c);
}
}
public static Character[] transformMiddleEx2PreEx(Character[] item){
LinkedStack<Character> s1=new LinkedStack<Character>();
LinkedStack<Character> s2=new LinkedStack<Character>();
for(int i=item.length-1;i>=0;i--){
Character c=item[i];
if(Character.isDigit(c)){
//是数字
s2.push(c);
}else if(c=='-'||c=='+'||c=='*'||c=='/'){
//运算符
//获取s1栈顶元素
Character s1top=s1.top();
//如果s1为空,或者栈顶为右括号,或者优先级比栈顶高或相等,将c压入s1
if(s1top==null||s1top==')'||compare(c,s1top)){
s1.push(c);
}
else{
//弹出s1栈顶,继续与下一个元素比较
boolean flag=false;
while(!flag) {
s1top = s1.pop();
if(s1top==null||s1top==')'||compare(c,s1top)){
s1.push(c);
flag=true;
}else{
s2.push(s1top);
}
}
}
}else if(c=='('||c==')'){
if(c==')'){
s1.push(c);
}
else if(c=='('){
boolean flag=false;
while(!flag){
Character s1top = s1.pop();
if (s1top==null||s1top == ')') {
flag=true;
}
else{
s2.push(s1top);
}
}
}
}
}
while(!s1.isEmpty()){
s2.push(s1.pop());
}
Character[] c=new Character[s2.size()];
int i=0;
while(!s2.isEmpty()){
c[i++]=s2.pop();
}
return c;
}
public static boolean compare(Character source,Character dest){
if(source=='*'||source=='/')return true;
if((source=='+'||source=='-')&&(dest=='+'||dest=='-'))return true;
return false;
}
}
中缀表达式转换为后缀表达式
- 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
- 从左至右扫描中缀表达式;
- 遇到操作数时,将其压s2;
- 遇到运算符时,比较其与s1栈顶运算符的优先级:
- 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
- 否则,若优先级比栈顶运算符的高,也将运算符压入s1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
- 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
- 遇到括号时:
- 如果是左括号“(”,则直接压入s1;
- 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
- 重复步骤2至5,直到表达式的最右边;
- 将s1中剩余的运算符依次弹出并压入s2;
- 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)
代码实现如下:
/***
* 转换中缀表达式为后缀表达式
* @param item
* @return
*/
public static Character[] transformMiddleEx2SufEx(Character[] item){
LinkedStack<Character> s1=new LinkedStack<Character>();
LinkedStack<Character> s2=new LinkedStack<Character>();
for(int i=0;i<item.length;i++){
Character c=item[i];
if(Character.isDigit(c)){
//是数字
s2.push(c);
}else if(c=='-'||c=='+'||c=='*'||c=='/'){
//运算符
//获取s1栈顶元素
Character s1top=s1.top();
//如果s1为空,或者栈顶为右括号,或者优先级比栈顶高或相等,将c压入s1
if(s1top==null||s1top=='('||compare2(c,s1top)){
s1.push(c);
}
else{
//弹出s1栈顶,继续与下一个元素比较
boolean flag=false;
while(!flag) {
s1top = s1.pop();
if(s1top==null||s1top=='('||compare2(c,s1top)){
s1.push(c);
flag=true;
}else{
s2.push(s1top);
}
}
}
}else if(c=='('||c==')'){
if(c=='('){
s1.push(c);
}
else if(c==')'){
boolean flag=false;
while(!flag){
Character s1top = s1.pop();
if (s1top==null||s1top == '(') {
flag=true;
}
else{
s2.push(s1top);
}
}
}
}
}
while(!s1.isEmpty()){
s2.push(s1.pop());
}
Character[] c=new Character[s2.size()];
int i=s2.size();
while(!s2.isEmpty()){
c[--i]=s2.pop();
}
return c;
}
/***
* 比较source运算符的优先级是否大于dest(不包含相等)
* @param source
* @param dest
* @return
*/
public static boolean compare2(Character source,Character dest){
if((source=='*'||source=='/')&&(dest=='+'||dest=='-'))return true;
return false;
}
后缀表达式的求值
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
代码实例:
public static Integer calculate(Character[] item){
LinkedStack<Integer> result=new LinkedStack<Integer>();
for(int i=0;i<item.length;i++){
if(Character.isDigit(item[i])){
result.push(Integer.valueOf(item[i].toString()));
}
else{
int b = result.pop();
int a = result.pop();
int res=0;
if (item[i]=='+') {
res = a + b;
} else if (item[i]=='-') {
res = a - b;
} else if (item[i]=='*') {
res = a * b;
} else if (item[i]=='/') {
res = a / b;
}
result.push(res);
}
}
return result.top();
}
前缀表达式的求值过程类似于后缀表达式,代码就不贴了,规则是:
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。