前缀表达式(波兰表达式)
1.前缀表达式的运算符位于操作数之前;
2.例如(3+4)x5-6的前缀表达式就是:-x+ 3 4 5 6;
计算机求值过程
从右至左扫描前缀表达式,遇到数字的时候将数字压入堆栈,遇到运算符的时候弹出栈顶的两个元素,用扫描到的这个运算符对它们做相应的运算,并将结果再次入栈;
重复上述过程,直到扫描到表达式的最左端,最后运算得出的值即是表达式的结果;
例如上面的: - x + 3 4 5 6前缀表达式
1.从右至左扫描,将6 5 4 3 依次压入栈中;
2.扫描到+号,则取出栈顶两个元素即3和4,进行运算得到7再加入栈中;
3.扫描到x号,则取出栈顶两个元素即7和5,得到结果35,加入到栈中;
4.扫描到-号,则取出35和6两个元素进行最后的运算,最终得到结果29=》运算完毕;
中缀表达式
就是我们常见的运算表达式,例如(3+4)x5-6;
中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作,就跟我们上面实现综合计算器一样, 它不仅需要两个栈来存储,并且在进行运算的时候还需要去判断运算符的优先级,因此肯定是不方便的;
而通过我们刚刚介绍的前缀表达式的计算机实现来讲,只要前缀表达式是正确的,我们不需要去判断运算符的优先级,并且在一个栈中就可以完成整个表达式的运算;
后缀表达式(逆波兰表达式)
与前缀表达式相似,只是运算符位于操作数之后;
例如(3+4)x5-6对应的后缀表达式就是:3 4 + 5 x 6 -;
计算机求值过程
从左至右扫描表达式,遇到数字时将数字压入堆栈,遇到运算符时弹出栈顶的两个数,用运算符对它们做相应的运算,并将结果再次入栈,重复上述过程直到表达式的最右端,最后运算得出的值即为表达式的结果(也就是跟前缀表达式求值是相反的);
例如上面的:3 4 + 5 x 6 -,的求值步骤如下:
1.从左至右扫描,将3,4压入堆栈;
2.扫描到+号,取出栈顶两个元素即3 4,进行运算得到7压入堆栈;
3.扫描到5,将其压入堆栈;
4.扫描到x号,取出栈顶两个元素即5,7进行运算 得到35,压入堆栈;
5.扫描到6,压入堆栈;
6.扫描到-号,取出35 6,进行运算,得到29,即最终结果,运算完毕(需要次顶元素在前,栈顶元素在后进行运算);
基于栈实现逆波兰计算器
要求
1输入一个逆波兰表达式(后缀表达式),我们使用系统提供的栈(Stack)计算其结果;
2.支持小括号和多位数整数,我们这里主要讲的是数据结构,因此计算器进行了简化,只支持整数运算;
思路分析
1.我们将逆波兰表达式以字符串的形式呈现,并且每个字符之间用空格或者其他符号隔开;
2.因为逆波兰表达式的计算是从左往右,因此我们将该字符串基于分隔符分割,得到所有的字符,并且存到List集合中;
3.创建一个Stack对象(Java.Util包下面的),遍历List集合,如果遍历到的元素是数字,则直接push进栈中;如果遍历得到的是符号,则取出栈中两个元素,与该符号进行运算;
4.再将运算的结果push进栈中;
5.扫描完成之后再取出栈中的元素(这个时候栈中只有一个元素,即最终的结果);
代码实现
/**
*
* @Author:Strine
* 逆波兰计算器的实现
* */
public static String getReverse(List<String> str){
Stack<String> stack = new Stack<>();
for (int i = 0; i < str.size(); i++) {
if (!isOper(str.get(i))){
stack.push(str.get(i));
}else {
String num1 = stack.pop(); //栈顶元素
String num2 = stack.pop(); //次顶元素
String ret = getRet(Integer.parseInt(num1), Integer.parseInt(num2), str.get(i));
stack.push(ret);
}
}
String ret= stack.pop();
return ret;
}
/**
*
* 判断是不是一个运算符
* */
public static boolean isOper(String oper){
return "+".equals(oper) || "-".equals(oper) || "*".equals(oper) || "/".equals(oper);
}
public static String getRet(int num1,int num2,String oper){
//用于存放计算的结果
int ret = 0;
switch (oper){
case "+":
ret=num1+num2;
break;
case "-":
ret=num2-num1;
break;
case "*":
ret=num1*num2;
break;
case "/":
ret=num2/num1;
break;
}
return String.valueOf(ret);
}
效果展示
计算:4*5-8+60+8÷2转成逆波兰表达式后的结果如下:
public static void main(String[] args) {
String str = "4 5 * 8 - 60 + 8 2 / +";
List<String> list = getList(str);
String ret = ReversePolish.getReverse(list);
System.out.println(str+"逆波兰表达式的结果是:"+ret);
}
public static List<String> getList(String str){
String[] tar = str.split(" ");
List<String> list = new ArrayList<>();
for (int i = 0; i < tar.length; i++) {
list.add(tar[i]);
}
return list;
}