规则
正常的表达式称为中缀表达式,我们用两个栈分别存储运算符和表达式,将存储表达式的栈称为A,存储符号的栈称为B。
从左到右扫描中缀表达式:
- 如果遇上数字,入A栈
- 遇上符号
- 比较算数优先级
- 对于括号,分左缀和右缀,只有当左缀和右缀同时对应时,左缀和右缀弹出栈B抵消,并将符号中的运算符一并弹出栈B,入栈A
- 无括号时
- 一个一个符号入栈B,当符号比B栈顶符号优先级高时,直接入B栈
- 当符号比B栈顶符号优先级低时,将B栈顶符号弹出入栈A,继续对比,直到该符号优先级大于栈顶符号或符号栈为空,该符号也入栈B
- 当扫描完成,将B栈所有符号依次弹出入栈A
例子
9+(3-1)*3+10/2
后缀(逆波兰表达式):
[9, 3, 1, -, 3, *, 10, 2, /, +, +]
计算规则
从左到右遍历表达式,遇到数字就进栈,遇到运算符就将栈顶两个数字出栈,配合运算符运算,运算结果入栈,直到栈只剩下一个数字,这就是表达式的结果了,完美出栈,华丽完成任务!
上述例子结果为20
代码实现
public class PolandNotation {
public static void main(String[] args) {
//先定义给逆波兰表达式
//(3+4)*5-6 34+5*6-
// String suffixExpression="3 4 + 5 * 6 -";
// //思路
// //1、先将字符串放到ArrayList中
// List<String> rpnlist = getListString(suffixExpression);
//2、将ArrayList传递给一个方法,遍历ArrayList 配合栈 完成计算
// int res=calculate(rpnlist);
// System.out.println(res);
String expression="9+(3-1)*3+10/2";
List<String> mediumlist = toMediumList(expression);
System.out.println(expression+"的中缀表达式为:"+mediumlist);
List<String> suffixExpression = mediumToSufixExpression(mediumlist);
System.out.println("逆波兰表达式为:"+suffixExpression);
System.out.println("结果为"+calculate(suffixExpression));
}
//将一个字符串转换成中缀表达式的list
public static List<String> toMediumList(String expression){
//用指针遍历字符串
int i=0;
//需要字符串拼接
String str;
//一个接收中缀表达式的集合
List<String> tomediumlist=new ArrayList<String>();
char c;//每遍历到一个字符,就放入c
do{
if((c=expression.charAt(i))<48||(c=expression.charAt(i))>57){
tomediumlist.add(""+c);
i++;
}else{
str="";//先将字符串置空
//要考虑拼接
while(i<expression.length()&&((c=expression.charAt(i))>=48&&(c=expression.charAt(i))<=57)){
str+=c;
i++;
}
tomediumlist.add(str);
}
}while(i<expression.length());
return tomediumlist;
}
//将一个中缀表达式转换成逆波兰表达式
public static List<String> mediumToSufixExpression(List<String> mediumExpression){
//表达式栈,因为没有出栈操作,直接用链表代替
// Stack<String> A=new Stack<String>();
List<String> A=new ArrayList<String>();
//符号栈
Stack<String> B=new Stack<String>();
for (String ele:mediumExpression) {
if(ele.matches("\\d+")){
A.add(ele);
}else if(ele.equals("(")){
B.push(ele);
}else if(ele.equals(")")){
while (!B.peek().equals("(")){
A.add(B.pop());
}
B.pop();
}else {
while(B.size()!=0&&getProperty(ele)<getProperty(B.peek())){
A.add(B.pop());
}
B.push(ele);
}
}
while(B.size()!=0){
A.add(B.pop());
}
return A;
}
//判断一个符号优先级
public static int getProperty(String s){
switch (s){
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
default:
System.out.println("不存在运算符");
return 0;
}
}
//将一个逆波兰表达式,依次将数据和运算符放入到ArrayList中
public static List<String> getListString(String suufixExpression){
String[] split=suufixExpression.split(" ");
List<String> list = new ArrayList<String>();
for (String ele:split) {
list.add(ele);
}
return list;
}
//计算对逆波兰表达式的运算
/*
* 1)从左至右扫描,将3和4压入堆栈
* 2)遇到+运算符,因此弹出4和3,计算3+4的值,得7,再压入栈
* 3)将5入栈
* 4)接下来是*运算符,因此弹出5和7,计算出7*5=35,将35入栈
* 最后是-运算符,计算出35-6的值,得29,由此得出最终结果*/
public static int calculate(List<String> ls){
Stack<String> stack =new Stack<String>();
for (String ele:ls) {
//用正则表达式取出数
if(ele.matches("\\d+")){//匹配多位数
stack.push(ele);
}else{
//pop出两个数,并运算,再入栈
int num2=Integer.parseInt(stack.pop());
int num1=Integer.parseInt(stack.pop());
int res=0;
if(ele.equals("+")){
res=num1+num2;
}else if(ele.equals("-")){
res=num1-num2;
}else if(ele.equals("*")){
res=num1*num2;
}else if(ele.equals("/")){
res=num1/num2;
}else {
throw new RuntimeException("运算符错误");
}
//把res入栈
stack.push(""+res);
}
}
//最后留在stack中的就是运算结果
return Integer.parseInt(stack.pop());
}
}