完整的逆波兰计算器实现
逆波兰bai表达式 rpn(Reverse Polish Notation)
逆波兰du表达式,它的zhi语法规定,表达式必须以逆dao波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
利用栈实现逆波兰计算器,主要的是我们人们计算的表达式一般都是中缀表达式比如:2+3;(2*3)+2等等,虽然我们人们看的一目了然但是利用栈的特性来做计算的时候常常非常麻烦,这时候就出现了个逆波兰表达式也称为后缀表达式比如:(2+3)/4的后缀表达式是 2 3 + 4/这个表达式在经过stack的运算的时候会非常的方便。现在来介绍如何从中缀表达式转为后缀表达式;
中缀表达式转后缀表达式的思想:
1、初始化两个栈 s1,s2
2、从左到右扫描中缀表达式
3、遇到数字的时候直接压入栈s2
4、遇到操作符的时候有几种情况:
1、遇到栈为空,或许s1栈顶的元素是“(”左括号直接入栈
2、当前扫描的元素比栈顶的优先级还高直接入栈
3、如果遇到右括号的时候 依次取出s1的栈顶元素压入s2中直到遇到s1栈顶元素是"("左括号,这时
把括号丢弃
4、假如当前操作符不比栈顶的优先级大的时候,取出s1的栈顶操作符压入s2然后重复2、3、4步骤
直到入栈
5、扫描完成后依次取出s1的栈顶元素压入s2中
6、逆序输出s2栈此时结果就是后缀表达式;
根据这个思想我们用代码来实现
public static List<String> toInfixConverSuffixPression(List<String> lists) {
Stack<String> s1 = new Stack<>();
Stack<String> s2 = new Stack<>();
for (String str : lists) {
//当扫描到是操作数的时候直接入栈s2
if ((str.charAt(0) >= 48) && (str.charAt(0) <= 57)) {
s2.push(str);
} else {//当字符串是操作符的时候
//当s1为空的时候直接入栈
if (s1.isEmpty()) {
s1.push(str);
} else {//当s1不为空的时候要进行判断
if (str.equals("(")) {//为左括号的时候直接入栈
s1.push(str);
} else if (str.equals(")")) {//为右括号的时候取出栈顶元素压入s2栈直到遇到左括号
String temp;//定义一个变量来接收栈顶元素
while (!(temp = s1.pop()).equals("(")) {
s2.push(temp);
}
} else if (priorityOper(str.charAt(0)) > priorityOper(s1.peek().charAt(0))) {//此时后来比较 是否比s1栈顶的运算符高如果比直接入栈
s1.push(str);
} else {//否则取出s1的栈顶元素放入s2在进行一次优先级比较,直到能入栈为止
while (true) {
if (s1.isEmpty() || s1.peek().equals("(") || priorityOper(str.charAt(0)) > priorityOper(s1.peek().charAt(0))) {
s1.push(str);
break;
}
s2.push(s1.pop());
}
}
}
}
}
//扫描完成后把s1剩余的元素依次取出压入s2
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
//将s2遍历add到list中
List<String> suffixPression = new ArrayList<>();
while (!s2.isEmpty()) {
suffixPression.add(s2.pop());
}
//list翻转的方法
Collections.reverse(suffixPression);
return suffixPression;
}
上面我们就完成了中缀转后缀表达式的算法
然后我们看下逆波兰计算器的思想:
逆波兰计算器的思想:
1、遍历后缀表达式
2、遇到数字直接压入一个Stack
3、遇到操作符取出Stack的顶元素和此顶元素计算完成后再压入Stack中
根据逆波兰计算器的思想我们来实现代码
public static int calcuate(List<String> lists) {
Stack<String> stack = new Stack<>();
for (String item : lists) {
if (item.matches("\\d+")) {
stack.push(item);
} else {
int num2 = Integer.parseInt(stack.pop());
int num1 = Integer.parseInt(stack.pop());
int res = 0;
if (item.equals("+")) {
res = num1 + num2;
} else if (item.equals("-")) {
res = num1 - num2;
} else if (item.equals("*")) {
res = num1 * num2;
} else if (item.equals("/")) {
res = num1 / num2;
} else {
throw new RuntimeException("符号错误");
}
stack.push(res + "");
}
}
return Integer.parseInt(stack.pop());
}
测试
public static void main(String[] args) {
String inFixExpression = "(3+4)*(2+23)";//中缀表达式
List<String> lists = toInfixExperssionList(inFixExpression);
List<String> suffixPression = toInfixConverSuffixPression(lists);
int result = calcuate(suffixPression);
System.out.println("最后的结果是"+result);
}
运行结果
最后的结果是175