网站首页 > java教程 正文
前言
看这篇文章之前,我们先要明确一些概念。
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为例:
image
中缀表达式得名于它是由相应的语法树的中序遍历的结果得到的。上面的二叉树中序遍历的结果就是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 ls
* @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()&&!stack.lastElement().equals("(")&&!comparePriority(express.charAt(i)+"",stack.lastElement())){
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(stack.lastElement())){
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("没有该类型的运算符!");
}
}
原文链接:https://www.jianshu.com/p/649c12a80fe8
相关链接:
https://www.cnblogs.com/lanhaicode/p/10776166.html
https://blog.csdn.net/weixin_44135121/article/details/91365242
猜你喜欢
- 2024-12-22 彻底理解Java反射以及动态代理中对反射的应用
- 2024-12-22 Java反射机制详解 java反射机制的作用是什么
- 2024-12-22 详解 Java 中的变量 java中变量的使用步骤
- 2024-12-22 Java 中的 Function:让转换逻辑更灵活
- 2024-12-22 手写一个Java的结构体实现Buffer和JavaBean的转换
- 2024-12-22 Java 整型数据有byte、short、int、long,它们之间有什么不一样?
- 2024-12-22 Java通过反射执行方法(获取方法) java通过反射获取字段的值
- 2024-12-22 java之反射(3)方法method java 反射method
- 2024-12-22 探讨 Java 中 valueOf 和 parseInt 的区别
- 2024-12-22 漫画:为什么Java里面的String对象是不可变的?
你 发表评论:
欢迎- 04-27微服务部署架构设计详解(图文全面总结)
- 04-27Java微服务架构选型与对比:一场技术流派的巅峰对决
- 04-27微服务架构下Java的最佳实践
- 04-27Java微服务架构选型:优雅拆分与高效整合
- 04-27微服务架构下的Java代码拆分策略:像拼图一样构建系统
- 04-27微服务架构下的Java最佳实践
- 04-27微服务架构下Java的挑战与机遇
- 04-27微服务架构下Java事务管理的艺术
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)