一、中缀表达式转后缀表达式
这里的运算思路跟我代码一样,所以我就直接借鉴的别人的
逆波兰表达式又称作后缀表达式,在四则混合运算的程序设计中用到。
例如:
1+2写成后缀表达式就是12+
4+5*(3-2)的后缀表达式就是4532-*+
后缀表达式在四则运算中带来了意想不到的方便,在生成过程中自动保持了优先级;
生成逆波兰表达式的算法如下:
我们首先的用两个栈结构来存储运算符和操作数,在java中有Stack类可以用;
从做到右遍历我们输入的中缀表达式:
1、如果是操作数的话,那么就直接压入存放操作数的堆栈;
2、如果是"("左括号的话,那么就直接压入存放运算符的堆栈;
3、如果是")"右括号的话,那么就从运算符堆栈中弹数据,并将弹出的数据压入到操作数堆栈中,直到遇到"("为止,这里值得注意的是,"("是必须要从运算符堆栈中弹出的,但是不压入到操作数堆栈,后缀表达式中是不包含括号的;
4、如果是其他符号,就是其他的运算符+-*/这些,那么就:
a、如果运算符堆栈为空,则直接压入运算符堆栈;
b、如果不为空且此时运算符堆栈的栈顶元素为左括号(不可能为')'),那么也是直接压入运算符堆栈中;
c、如果此时遍历到的元素的优先级比此时运算符堆栈栈顶元素的优先级高,则直接压入运算符堆栈;
d、如果正在遍历的元素的优先级和运算符堆栈栈顶的元素的优先级相等或者更小,则需要将栈顶元素弹出并且放到操作数堆栈 中,并且将正在遍历的元素压入到运算符堆栈,其实运算符堆栈中的元素顺序就是优先级的顺序;
5、直到遍历完表达式,此时还需要将运算符堆栈中的所有元素压入到操作数堆栈中,算法完成。
以下是我的代码:
import java.util.*;
public class CPrograms2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[] input = sc.nextLine().toCharArray();
char[] operator = new char[input.length]; //运算符栈
char[] result = new char[input.length]; //用来保存后缀结果
int ir = 0,io = 0; //ir为result下标,表示存储下一个元素待插入的位置;io为operator下包,同ir
for (int i=0;i<input.length;i++){ //遍历每一个字符
char c = input[i];
if (c >= '0' && c <= '9') //c如果是数字,则直接放到result中
result[ir++] = c;
else if (c == '(') //'('直接放到operateor中
operator[io++] = c;
else if (c == ')'){ //如果c是')',则把上一个'('和c之间的所有运算符都放到result中,最后io指向待插入位置的下标
while (operator[io] != '(')
result[ir++] = operator[io--];
} else if(io == 0) //c为+-*/时,io为0,直接把c放到operator中
operator[io++] = c;
else { //c为+-*/时,io不为0。注意:( ) * + - /的ASCII码分别为40 41 42 43 45 47
if (operator[io-1]=='(') //如果operator[io-1]为'(',优先级最低,直接放到operator中
operator[io] = c;
else{ //c不为'(',则为+-*/,比较c与上一个运算符的优先级。+-为0,*/为1
int priorityPre = operator[io-1]==42 || operator[io-1]==47 ? 1 : 0; //获取上一个运算符的优先级
int priorityCur = c==42 || c==47 ? 1 : 0; //获取c的优先级
if (priorityCur <= priorityPre){ //比上一个优先级低,上一个出栈,c保留
result[ir++] = operator[io-1];
operator[io-1] = c;
}else //比上一个优先级高,c直接保留
operator[io++] = c;
}
}
}
while (io > 0) //将operator中剩下的运算符按出栈顺序保存到result中
result[ir++] = operator[--io];
for (int i=0;i<input.length;++i) //打印结果
System.out.print(result[i]);
}
}
二、中缀表达式转前缀表达式
接下来是中缀表达式转前缀表达式,与转后缀不同的地方是:从右到左遍历(注意'('、')'的互换),求出第一个结果之后,然后再把结果从后往前打印(类似于出栈操作)即是前缀表达式。以下是输入案例,仅供参考。
中序表达式 | 2*3/(2-1)+3*(4-1) |
前序表达式 | +/*23-21*3-41 |
后序表达式 | 23*21-/341-*+ |
以下注释“********”的代码是与转后缀表达式代码不同的地方(上面)
import java.util.*;
public class CPrograms2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[] input = sc.nextLine().toCharArray();
char[] operator = new char[input.length];
char[] result = new char[input.length]; //用来保存后缀结果
int ir = 0,io = 0; //ir为result下标,表示存储下一个元素待插入的位置;io为operator下包,同ir
for (int i=input.length-1;i>=0;i--){ //**************倒过来遍历每一个字符
char c = input[i];
if (c >= '0' && c <= '9') //c如果是数字,则直接放到result中
result[ir++] = c;
else if (c == ')') //*********因为是倒过来的,所以这里和下面程序的'('与')'互换
operator[io++] = c;
else if (c == '('){ //*********如果c是'(',则把上一个'('和c之间的所有运算符都放到result中,最后io指向待插入位置的下标
while (operator[io] != ')') //*********
result[ir++] = operator[io--];
} else if(io == 0) //c为+-*/时,io为0,直接把c放到operator中
operator[io++] = c;
else { //c为+-*/时,io不为0。注意:( ) * + - /的ASCII码分别为40 41 42 43 45 47
if (operator[io-1]==')') //**********如果operator[io-1]为'(',优先级最低,直接放到operator中
operator[io] = c;
else{ //c不为'(',则为+-*/,比较c与上一个运算符的优先级。+-为0,*/为1
int priorityPre = operator[io-1]==42 || operator[io-1]==47 ? 1 : 0; //获取上一个运算符的优先级
int priorityCur = c==42 || c==47 ? 1 : 0; //获取c的优先级
if (priorityCur <= priorityPre){ //比上一个优先级低,上一个出栈,c保留
result[ir++] = operator[io-1];
operator[io-1] = c;
}else //比上一个优先级高,c直接保留
operator[io++] = c;
}
}
}
while (io > 0) //将operator中剩下的运算符按出栈顺序保存到result中
result[ir++] = operator[--io];
for (int i=ir-1;i>=0;i--) //*********倒过来打印结果
System.out.print(result[i]);
}
}
三、如果通过前缀、后缀表达式求中缀表达式的值
对于前缀表达式,从右往左读取,遇到运算符时,把运算符右边最近的两个数进行运算(如‘3*-124’就是‘3*(-1)4’),以此类推,知道只剩下一个数即为结果。
对于后缀表达式,从左往右读取,遇到运算符时,把运算符左边最近的两个数进行运算(如‘412-*3’就是‘4(-1)*3’),以此类推,知道只剩下一个数即为结果。