之前一篇文章讲了逆波兰式计算器的实现,我们一般使用的是前缀表达式,但是对于计算机来说,后缀表达式是一种更好的选择。下面讲下中缀表达式转换为后缀表达式。
分析
中缀表达式之前说过,就比如1+((2+3)*4)-5这样的计算表达式,但是如何转换成后缀表达式呢?
1,定义两个栈s1和s2,运算符栈和用于存储中间结果的栈s2
2,从左往右扫描中缀表达式
3,遇到操作数,将其压入s2。
4,遇到(,直接将它压入s2
5,遇到),则一直弹出s1里面的有运算符,直到遇到(为止,并将弹出的结果压入s2,之后将一对括号丢弃
6,遇到有运算符时,先与栈顶的符号优先级做一个比较,优先级小于等于栈顶的字符,将栈顶的运算符弹出,反复比较,直到比栈顶的优先级大,就直接将该字符压入s1.
7,重复以上步骤,将s1剩余的操作符依次弹出并加到s2中。
8,s2中弹出,然后在做反序,就是后缀表达式的结果
代码实现
说明:本例中的用于保存结果的栈s2用list集合代替,因为用栈的话,最后的结果还需要做反序,十分不方便
package cn.mrlij.stack;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* 中缀表达式转后缀表达式
*/
public class PolandNotation {
public static void main(String[] args) {
String exp = "1+((2+3)*4)-5";
List<String> toinfix = toinfixList(exp);
System.out.println(toinfix);
List<String> list = tosuffList(toinfix);
System.out.println(list);
}
/**
* 遍历表达式,并将遍历的结果放入list中
* @param exp 表达式
* @return
*/
public static List<String> getStrList(String exp){
String arr[] = exp.split(" ");//将字符串遍历得到数组
List<String> list = new ArrayList<>();
for(String str : arr){
list.add(str);
}
return list;
}
//将前缀表达式转换为相应的list,便于操作
public static List<String> toinfixList(String str){
List<String> list = new ArrayList<>();
String s = "";//用于字符串拼接
char c = ' ';//用于保存字符
int index = 0;//定义索引
//
do{
//非数字,添加到list中 0的ASCII为48,9的ASCII为57
if(str.charAt(index)<48 || str.charAt(index)>57 ){
list.add(""+str.charAt(index));
index++;
}else {
//为数字
while (index<str.length()&&(str.charAt(index)>=48 && str.charAt(index)<=57)){
s = "";//将s清空
//往后找数字,是否存在多位数字
s += str.charAt(index);
index++;
}
list.add(s);
}
}while (index<str.length());
return list;
}
//前缀表达式转换成后缀表达式的方法
public static List<String> tosuffList(List<String> list){
Stack<String> s1 = new Stack<>();//定义一个用于存放前缀表达式字符的栈
List<String> s2 = new ArrayList<>();//用于存放后缀表达式字符的集合
//遍历list
for(String item : list){
if(item.matches("\\d+")){
s2.add(item);
}else if(item.equals("(")){
s1.push(item);
}else if(item.equals(")")){
//遇到),依次弹出s1中的操作符号,直到遇到(为止,此时将一对括号丢弃
while(!s1.peek().equals("(")){
s2.add(s1.pop());
}
s1.pop();
}else {
while (s1.size()!=0&&(Oper.getValue(s1.peek())>=Oper.getValue(item))){
s2.add(s1.pop());
}
s1.push(item);
}
}
while (s1.size()!=0){
s2.add(s1.pop());
}
return s2;
}
//计算表达式
public static int calc(List<String> list ){
//创建存放字符串的栈
Stack<String> stack = new Stack<>();
//遍历list
for (int i = 0;i<list.size();i++){
//正则表达式匹配是否是数字
if(list.get(i).matches("\\d+")){
stack.push(list.get(i));//是数字则放入栈中
}else {
int num2 = Integer.parseInt(stack.pop());//弹出数字1
int num1 = Integer.parseInt(stack.pop());//弹出数字2
int res = 0;
//进行运算
if(list.get(i).equals("+")){
res = num1 + num2;
}else if(list.get(i).equals("-")){
res = num1 - num2;
}else if(list.get(i).equals("*")){
res = num1 * num2;
}else if(list.get(i).equals("/")){
res = num1/num2;
}else {
throw new RuntimeException("不是操作符号!");
}
stack.push(""+res);
}
}
//留在栈中的值就是最后的计算表达式结果
return Integer.parseInt(stack.pop());
}
}
class Oper{
public static int ADD = 1;
public static int SUB = 1;
public static int MUL = 2;
public static int DIV = 2;
public static int getValue(String oper){
int res = 0;
switch (oper){
case "+": res = ADD;
break;
case "-": res = SUB;
break;
case "*": res = MUL;
break;
case "/": res = DIV;
break;
default:
System.out.println("操作符不存在!");
break;
}
return res;
}
}