栈的前缀_中缀_后缀表达式
三种表达式
- 前缀表达式,又称为波兰式,在前缀表达式中,运算符位于操作数之前。
- 例如(3+4)*5-6,其前缀表达式为:- *+3456
- 中缀表达式即我们人类日常使用的数学运算
- 后缀表达式,又称为逆波兰表达式,在后缀表达式中,运算符位于操作数之后。
- 例如(3+4)*5-6,其后缀表达式为:34+5 *6-
转换方法
-
中缀转前缀
确定中缀表达式的运算顺序,然后一层一层加上括号,相当于将一个括号的内容看作了一个数,然后从最里面的括号开始运算。 -
例子:
1+(2+3)*4-5 =>((1+((2+3)*4))-5)
1、(2+3) =>+23
2、((2+3)*4) => *+234
3、(1+((2+3)*4)) => +1 *+234
4、((1+((2+3)*4)) -5)=> -+1 *+2345 -
中缀转后缀
步骤和中缀转前缀类似,不同的是,后缀表达式中的运算符位于操作数之后 -
例子:
1+(2+3)*4-5 =>((1+((2+3)*4))-5)
1、(2+3) =>23+
2、((2+3)*4) => 23+4 *
3、(1+((2+3)*4)) => 123+4 *+
4、((1+((2+3)*4)) -5)=> 123+4 *+5-
前缀、后缀表达式原理的计算器求值
-
前缀表达式:
1、从右至左扫描前缀表达式,遇到数字时就将数字压入堆栈
2、遇到运算符时,弹出栈顶和次顶的两个数,用该运算符对这两个数做相应的运算,并将结果入栈。
3、重复步骤1和步骤2,直到表达式被扫描完,最后运算得到值。 -
后缀表达式:
1、从左至右扫描前缀表达式,遇到数字时就将数字压入堆栈
2、遇到运算符时,弹出栈顶和次顶的两个数,用该运算符对这两个数做相应的运算,并将结果入栈。
3、重复步骤1和步骤2,直到表达式被扫描完,最后运算得到值。
中缀转后缀表达式代码实现
思路
1、 初始化两个栈,s1暂时存储运算符,s2存储数字和运算符
2、从左至右扫描中缀表达式,扫描到数字存入s2
3、 扫描到运算符时,
1)如果s1为空栈,或者栈顶运算符为“(”,则直接入s1栈
2)如果该运算符的优先级比栈顶运算符的优先级高,也直接入s1栈
3)如果1)和2)都不满足,就将当前s1栈的栈顶元素取出,并令其入s2栈,然后再重复1)~3)的步骤,直到希望入栈的运算符入s1栈
4、扫描到“(”就直接入s1栈,遇到“)”则一直取出s1栈中的运算符并存入s2栈,直到s1栈取出一个“(”后(该"("不存入s2栈),停止取出s1栈中的运算符,而该“)”也不存入s1和s2栈
5、重复2~4,直到中缀表达式被遍历完
6、将s1栈中的运算符依次取出并存入s2栈中
7、s2栈中的数据再全部取出,并逆序,就得到了对应的后缀表达式
代码实现
public static List<String> infixListToRpnList(List<String> list) {//将中缀表达式转为逆波兰表达式
List<String> rpnList=new ArrayList<String>();
Stack<String> datastack=new Stack<String>();//存储中间结果和符号
Stack<String> operstack=new Stack<String>();//暂时存储符号
int num2=0;
int num1=0;
int result=0;
String oper=null;
for(String item:list) {
if(item.matches("\\d+")) {//如果是数字就入数栈
datastack.push(item);
}else {
if(operstack.size()==0||operstack.peek().equals("(")) {//如果栈空或者栈顶是"(",直接插入数据
operstack.push(item);
}else if(item.equals(")")){//如果item是")",则将符号栈中的运算符取出,直到取出一个"("后为止
while(true) {
if(operstack.peek().equals("(")) {
operstack.pop();
break;
}
datastack.push(operstack.pop());
}
}else if(priority(item)>priority(operstack.peek())) {//如果优先级大于栈顶运算符的优先级,也直接插入
operstack.push(item);
}else if(priority(item)<=priority(operstack.peek())){//如果优先级小于等于栈顶运算符的优先级,
datastack.push(operstack.pop());
//将当前运算符栈的栈顶元素插入s2,然后再循环判断新栈顶元素的优先级和希望入栈的运算符的优先级
while(true) {
if(operstack.size()==0||operstack.peek().equals("(")) {
operstack.push(item);
break;
}else if(priority(item)>priority(operstack.peek())) {
operstack.push(item);
break;
}else {
datastack.push(operstack.pop());
}
}
}
}
}
//将符号栈中剩下的运算符全部插入数栈
while(operstack.size()!=0) {
datastack.push(operstack.pop());
}
for(String item:datastack) {
rpnList.add(item);
}
return rpnList;
}
public static void main(String[] args) {
List<String> list=infixToArrayList("4*5-8+60+8/2");
list=infixListToRpnList(list);
for(String i:list) {
System.out.println(i);
}
}
运行结果
4
5
*
8
-
60
+
8
2
/
+
后缀表达式实现简易整数计算器
思想
从左至右扫描后缀表达式,遇到数字时,就将数字插入栈中,遇到运算符就从栈中取出2个数字,根据运算符令这2个数字做运算,得到的结果插入栈中。重复上述过程,直到表达式被扫描完毕,最后完成运算得到结果。
代码实现
public class ReversePolishNotation {
public static void main(String[] args) {
List<String> list=infixToArrayList("4*5-8+60+8/2");
list=infixListToRpnList(list);
for(String i:list) {
System.out.println(i);
}
System.out.printf("计算结果%d\n",calculator(list));
}
public static int priority(String s) {//优先级
if(s.equals("*")||s.equals("/")) {
return 1;
}else if(s.equals("+")||s.equals("-")) {
return 0;
}else {
return -1;
}
}
public static List<String> infixToArrayList(String infix){//将中缀表达式放入链表
List<String> list=new ArrayList<String>();
char ch=' ';
String keepStr="";
int index=0;
while(index<infix.length()) {
ch=infix.charAt(index);
if(ch<48||ch>57) {
list.add(ch+"");
index++;
}else {
while((index<infix.length())&&ch>=48&&ch<=57) {
keepStr+=ch;
index++;
if(index>=infix.length()) {
break;
}
ch=infix.charAt(index);
}
list.add(keepStr);
keepStr="";
}
}
return list;
}
public static List<String> infixListToRpnList(List<String> list) {//将中缀表达式转为逆波兰表达式
List<String> rpnList=new ArrayList<String>();
Stack<String> datastack=new Stack<String>();//存储中间结果和符号
Stack<String> operstack=new Stack<String>();//暂时存储符号
int num2=0;
int num1=0;
int result=0;
String oper=null;
for(String item:list) {
if(item.matches("\\d+")) {//如果是数字就入数栈
datastack.push(item);
}else {
if(operstack.size()==0||operstack.peek().equals("(")) {//如果栈空或者栈顶是"(",直接插入数据
operstack.push(item);
}else if(item.equals(")")){//如果item是")",则将符号栈中的运算符取出,直到取出一个"("后为止
while(true) {
if(operstack.peek().equals("(")) {
operstack.pop();
break;
}
datastack.push(operstack.pop());
}
}else if(priority(item)>priority(operstack.peek())) {//如果优先级大于栈顶运算符的优先级,也直接插入
operstack.push(item);
}else if(priority(item)<=priority(operstack.peek())){//如果优先级小于等于栈顶运算符的优先级,
datastack.push(operstack.pop());
//将当前运算符栈的栈顶元素插入s2,然后再循环判断新栈顶元素的优先级和希望入栈的运算符的优先级
while(true) {
if(operstack.size()==0||operstack.peek().equals("(")) {
operstack.push(item);
break;
}else if(priority(item)>priority(operstack.peek())) {
operstack.push(item);
break;
}else {
datastack.push(operstack.pop());
}
}
}
}
}
//将符号栈中剩下的运算符全部插入数栈
while(operstack.size()!=0) {
datastack.push(operstack.pop());
}
for(String item:datastack) {
rpnList.add(item);
}
return rpnList;
}
public List<String> save(String rpn){//将表达式处理,放入List中
String []rpnStr=rpn.split(" ");//通过分割符将每个数据存放到字符串数组中
List<String> list=new ArrayList<String>();
for(String item:rpnStr) {//将字符串数组中的每一个元素都存放进List中
list.add(item);
}
return list;
}
public static int calculator(List<String> list) {//运算
Stack<String> stack=new Stack<String>();
for(String item:list) {
if(item.matches("\\d+")) {//正则表达式判断是否是数字
stack.push(item);
}else {//不是数字就说明是运算符
int num2=Integer.parseInt(stack.pop());
int num1=Integer.parseInt(stack.pop());//取出两个数字
int result=0;
if(item.equals("+")) {
result=num1+num2;
}else if(item.equals("-")) {
result=num1-num2;
}else if(item.equals("*")) {
result=num1*num2;
}else if(item.equals("/")) {
result=num1/num2;
}else {
throw new RuntimeException("该字符不是运算符");
}
stack.push(""+result);//做完运算后,要让数据入栈
}
}
return Integer.parseInt(stack.pop());
}
}
运行结果
4
5
*
8
-
60
+
8
2
/
+
计算结果76