逆波兰表达式、波兰表达式【数据结构与算法】

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

逆波兰表达式、波兰表达式【数据结构与算法】
逆波兰表达式、波兰表达式【数据结构与算法】
1.前缀表达式⼜称波兰式,前缀表达式的运算符位于操作数之前。

⽐如:- × + 3 4 5 6
2.中缀表达式就是常见的运算表达式,如(3+4)×5-6
3.后缀表达式⼜称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后,⽐如:3 4 + 5 × 6 -
⼈类最熟悉的⼀种表达式1+2,(1+2)3,3+42+4等都是中缀表⽰法。

对于⼈们来说,也是最直观的⼀种求值⽅式,先算括号⾥的,然后算乘除,最后算加减,但是,计算机处理中缀表达式却并不⽅便。

然后我们还需明确⼀些概念,下⾯通过我们最熟悉的中缀表达式画出⼀棵语法树来直观认识⼀下前后缀表达式的⽣成。

以A+B*(C-D)-E*F为例:
中缀表达式得名于它是由相应的语法树的中序遍历的结果得到的。

上⾯的⼆叉树中序遍历的结果就是A+B*(C-D)-E*F。

前缀表达式是由相应的语法树的前序遍历的结果得到的。

上图的前缀表达式为- + A * B - C D * E F
后缀表达式⼜叫做逆波兰式。

它是由相应的语法树的后序遍历的结果得到的。

上图的后缀表达式为:A B C D - * + E F * -
下⾯我们关注两个点:
1.如何根据⼀个逆波兰表达式求出运算结果?
2.如果将⼀个中缀表达式转换成后缀表达式(逆波兰表达式)
⼀.通过逆波兰表达式计算结果
我们先看⼀个例⼦...后缀表达式3 4 + 5 × 6 -的计算
1.从左⾄右扫描,将3和4压⼊堆栈;
2.遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做⽐较),计算出3+4的值,得7,再将7⼊栈;
3.将5⼊栈;
4.接下来是×运算符,因此弹出5和7,计算出7×5=35,将35⼊栈;
5.将6⼊栈;
6.最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

从上⾯的过程我们如何编写代码实现呢?
可以采⽤⼀个辅助的栈来实现计算,扫描表达式从左往右进⾏,如果扫描到数值,则压进辅助栈中,如果扫描到运算符,则从辅助栈中弹出两个数值参与运算,并将结果压进到栈中,当扫描表达式结束后,栈顶的数值就是表达式结果。

下⾯是代码实现(Java)
/**
* 通过逆波兰表达式计算结果
* @param express
* @return
*/
//求逆波兰表达式的值
public static int calcRevPolishNotation(String express){
Stack<String> stack = new Stack<>();
for (int i = 0; i <express.length() ;i++) {
// 普通数值的处理
if ((express.charAt(i) + "").matches("\\d")){
stack.push(express.charAt(i) + "");
// + - * / 运算符的处理
}else if ((express.charAt(i) + "").matches("[\\+\\-\\*\\/]")){
String k1 = stack.pop();
String k2 = stack.pop();
// 计算结果
int res = calcValue(k1, k2, (express.charAt(i) + ""));
stack.push(res+"");
}
}
return Integer.valueOf(stack.pop());
}
//根据运算符计算结果
private static int calcValue(String k1, String k2, String c) {
switch(c){
case "+":
return Integer.valueOf(k1)+Integer.valueOf(k2);
case "-":
return Integer.valueOf(k2)-Integer.valueOf(k1);
case "*":
return Integer.valueOf(k1)*Integer.valueOf(k2);
case "/":
return Integer.valueOf(k2)/Integer.valueOf(k1);
default:
throw new RuntimeException("没有该类型的运算符!");
}
}
⼆.中缀表达式转换为后缀表达式(逆波兰表达式)
中缀表达式转后缀表达式主要⽤到了栈进⾏运算符处理,队列进⾏排序输出,规则为:
1.数字直接⼊队列
2.运算符要与栈顶元素⽐较
 ①栈为空直接⼊栈
 ②运算符优先级⼤于栈顶元素优先级则直接⼊栈
 ③⼩于或等于则出栈⼊列,再与栈顶元素进⾏⽐较,直到运算符优先级⼩于栈顶元
 素优先级后,操作符再⼊栈
3.操作符是 ( 则⽆条件⼊栈
4.操作符为 ),则依次出栈⼊列,直到匹配到第⼀个(为⽌,此操作符直接舍弃,(直接出栈舍弃
代码实现(Java)
/**
* 将中缀表达式转换为后缀表达式(逆波兰表达式)
* @param express
* @return
*/
public static String transfer(String express){
Stack<String> stack = new Stack<>();
List<String> list= new ArrayList<>();
for (int i=0;i<express.length();i++){
if ((express.charAt(i)+"").matches("\\d")){
list.add(express.charAt(i)+"");
}else if((express.charAt(i)+"").matches("[\\+\\-\\*\\/]")){
//如果stack为空
if (stack.isEmpty()){
stack.push(express.charAt(i)+"");
continue;
}
//不为空
//上⼀个元素不为(,且当前运算符优先级⼩于上⼀个元素则,将⽐这个运算符优先级⼤的元素全部加⼊到队列中while (!stack.isEmpty()&&!stElement().equals("(")&&!comparePriority(express.charAt(i)+"",stElement())){ list.add(stack.pop());
}
stack.push(express.charAt(i)+"");
}else if(express.charAt(i)=='('){
//遇到左⼩括号⽆条件加⼊
stack.push(express.charAt(i) + "");
}else if(express.charAt(i)==')'){
//遇到右⼩括号,则寻找上⼀堆⼩括号,然后把中间的值全部放⼊队列中
while(!("(").equals(stElement())){
list.add(stack.pop());
}
//上述循环停⽌,这栈顶元素必为"("
stack.pop();
}
}
//将栈中剩余元素加⼊到队列中
while (!stack.isEmpty()){
list.add(stack.pop());
}
StringBuffer stringBuffer = new StringBuffer();
//变成字符串
for (String s : list) {
stringBuffer.append(s);
}
return stringBuffer.toString();
}
/**
* ⽐较运算符的优先级
* @param o1
* @param o2
* @return
*/
public static boolean comparePriority(String o1,String o2){
return getPriorityValue(o1)>getPriorityValue(o2);
}
/**
* 获得运算符的优先级
* @param str
* @return
*/
private static int getPriorityValue(String str) {
switch(str){
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
default:
throw new RuntimeException("没有该类型的运算符!"); }
}。

相关文档
最新文档