一、前言:
平时我们使用计算器做计算时,书写或者输出计算器的表达式称之为中缀表达式,而若是用计算器做计算时,计算器的底层其实将其转化成为了后缀表达式,,也叫逆波兰表达式当然了,有中缀 ,后缀,就会有前缀表达式,但是前缀表达式我们很少用到。计算器就是将其转化为后缀表达式在进行一个双栈算术表达式的求值算法,这个算法好像是一个叫Dijkstra的人整出来的,这不是重点,下面我们直接上思想与代码
如:
1+((2+3)*4)-5---->中缀表达式
1, 2, 3, +, 4, *, +, 5, - ------>后缀表达式
前缀略【不是重点】
二:思路:
1、创建一个符号栈,装运算符的栈;
在创建一个ArrayList【这我做了一个改变,因为我觉得创建的数字栈,只有压入数据的操作,没有弹出元素的操作,并且最终需要逆序打印栈中的元素才是我们想要的逆波兰表达式顺序】
2、先遍历传入的表达式字符串,逐一遍历
3、每当遍历一个字符,
判断:
1)、如果是数字则计入到数字集合(list);
2)、如果是左括号,则入符号栈(stack);
3)、如果是右括号,则在符号栈弹出元素,并加入到数字集合,直到遇到栈顶元素为左括号为止,并且将当前的左括号弹出【注意,这步不能少】;
4)、如果是运算符,则先判断待压入运算符的优先级与当前符号栈栈顶元素的优先级,若
前者小于或等于后者,则在符号栈不为空的条件下,依次弹出元素,并加入到数字集合当中,直到前者大于后者为止;反之,则直接压入到符号栈;
5)、遍历完表达式字符串后,弹出符号栈中所剩的符号,并加入到数字集合中
6)、最终遍历打印出数字集合中的所有元素就为当前表达式的逆波兰表达式。
三:代码
package edu.xufe.arrayStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class PolandNotation02 {
public static void main(String[] args) {
String s = "1+((2+3)*4)-5";
List<String> infixException = getInfixException(s);
System.out.println("中缀表达式为:" + infixException);
List<String> sufixExceptionList = getSufixExceptionList(infixException);
System.out.println("后缀表达式为:" + sufixExceptionList);
System.out.println(calculator(sufixExceptionList));
}
// 将一个中缀表达式字符串转化成为一个list,因为这样方便去遍历操作表达式
// s:"1+((2+3))×4)-5"
public static List<String> getInfixException(String str) {
List<String> list = new ArrayList<String>();
int i = 0;// 遍历字符串的变量
String s;// 用来拼接多位数的变量
char c;// 遍历的字符存到c中
do {
// 非数字,就直接存到栈中
if ((c = str.charAt(i)) < 48 || (c = str.charAt(i)) > 57) {
list.add("" + c);
i++;
} else {// 是数字,注意:还要判断是否是多位数
s = "";// 初始化【清空】
// 对应ASCLL码
while (i < str.length() && (c = str.charAt(i)) >= 48 && (c = str.charAt(i)) <= 57) {
s += c;
i++;
}
list.add(s);
}
} while (i < str.length());
return list;
}
// 中缀表达式转化成为后缀表达式
public static List<String> getSufixExceptionList(List<String> list) {
Stack<String> symbolStack = new Stack<String>();// 符号栈
// 因为不用弹出字符,且最终要逆序打印才是后缀表达式的顺序,所以可用来list代替
ArrayList<String> numList = new ArrayList<String>();// 数字集合
for (String item : list) {
// 是数字
if (item.matches("\\d+")) {
numList.add(item);// 将数字加入到数字集合
}
// 是左括号"("
else if (item.equals("(")) {
symbolStack.push(item);// 将符号加入到运算符栈中
}
// 是右括号")"
// 则将符号栈中的运算弹出并添加到数字集合当中,直到遇到左括号"("结束,且把两个括号消掉
else if (item.equals(")")) {
// 栈顶元素不是"("
while (! symbolStack.peek().equals("(")) {
numList.add(symbolStack.pop());
}
symbolStack.pop();// 弹出左括号
}
// 是运算符
else {
// 待进入符号栈的运算符优先级小于或等于当前符号栈栈顶元素优先级,则把当前的栈顶元素弹出并加入到数字栈,直到大于为止
while (symbolStack.size() != 0 && priority.compare(item) <= priority.compare(symbolStack.peek())) {
numList.add(symbolStack.pop());
}
symbolStack.push(item);// 将当前运算符加入到符号栈
}
}
while (symbolStack.size() != 0) {
numList.add(symbolStack.pop());// 将符号栈中所有元素都加入到数字集合中
}
return numList;
}
/*
* 计算的方法
*/
public static int calculator(List<String> list) {
Stack<String> stack = new Stack<String>();
for(String s : list) {
if(s.matches("\\d+")) {//判断是否是数字,双斜杠的意思是java中单斜杠是转义字符,所以需多加一个斜杠
stack.push(s);
}else {//是运算符
int num1 = Integer.parseInt(stack.pop());//弹出的栈顶元素
int num2 = Integer.parseInt(stack.pop());//弹出的次顶元素
int res = 0;
if(s.equals("+")) {
res = num2 + num1;
}
else if(s.equals("-")) {
res = num2 - num1;
}
else if(s.equals("*")) {
res = num2 * num1;
}
else if(s.equals("/")) {
res = num2 / num1;
}
else {
throw new RuntimeException("改表达式中含有不合法符号");
}
stack.push(res+"");
}
}
return Integer.parseInt(stack.pop());
}
}
// 比较优先级
class priority {
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;
public static int compare(String str) {
int result = 0;
switch (str) {
case "+":
result = ADD;
break;
case "-":
result = SUB;
break;
case "*":
result = MUL;
break;
case "/":
result = DIV;
break;
default:
System.out.println("输入有误");
break;
}
return result;
}
}