中缀表达式转后缀表达式并计算结果
目录
- 1 栈的概念
- 2 何谓中缀表达式
- 3 后缀表达式(逆波兰)
- 3.1 概念以及案例
- 3.2 求解方法
- 3.2.1 流程图
- 3.2.2 推导相等优先级为何弹出栈顶
- 3.2.3 案例
- 代码
1 栈的概念 容器,先进后出规则;如图为表达式:a+(b*c) 逐个操作符、操作数入栈过程;出栈为该过程逆序
文章图片
2 何谓中缀表达式 型如:a - b + c 的普通算术表达式,我们称之为中缀表达式。
3 后缀表达式(逆波兰) 3.1 概念以及案例 中缀表达式:a - b + c ,转化为后缀表达式:ab-c+;
后缀表达式运算规则:
- 遇到操作数直接入栈,遇到操作符,从栈顶弹出两个操作数,并计算如下表达式结果压栈,直至最终弹出栈中最后一个数即停止算法,该记法的表达式称为后缀表达式
后出栈操作数(两数中更靠近栈底者) (操作符[+_*/]) 先出栈操作数(栈顶)
- ab-c+计算过程如下图:
文章图片
3.2 求解方法 3.2.1 流程图
文章图片
3.2.2 推导相等优先级为何弹出栈顶
只关注相同有优先级下是否弹出栈顶
- 先加,后加减乘除
中缀表达式 | 后缀表达式 |
---|---|
a + b + c | abc++ 或 ab+c+ |
a + b - c | ab+c- 或 abc-+ |
- 先减,后加减乘除
中缀表达式 | 后缀表达式 |
---|---|
a - b + c | ab-c+ |
a - b - c | ab-c- |
- 先乘,后加减乘除
中缀表达式 | 后缀表达式 |
---|---|
a * b * c | abc** 或 abc |
a * b / c | abc/ 或 abc/ |
- 先除,后加减乘除
中缀表达式 | 后缀表达式 |
---|---|
a / b * c | ab/c* |
a / b / c | ab/c/ |
对比上述4种情景,取其交集,故在当前位等于栈顶优先级时,弹出栈顶。
3.2.3 案例
- 中缀表达式:2{1+2[4/(8-6)+7]}
文章图片
- 后缀表达式:2 1 2 4 8 6 - / 7 + * + *
- 负数前加 0,例如 -5 * 3 转为 0 - 5 * 3
- 读取连续数字,推导过程中使用的都是单个操作数,但是实际使用时肯定有多位数的操作,所以当读取到一个数字位时,则判断下一位是否为数字,读出连续数字。
import java.util.*;
import java.lang.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("\r\n输入一个合法中缀表达式:");
while (scanner.hasNextLine()) {
// 1.读取一行输入
String nextLine = scanner.nextLine();
List express = new ArrayList<>();
// 后缀表达式容器
// 2.中缀转后缀
handle(nextLine, express);
System.out.print("后缀表达式:" + express);
// 3.计算后缀表达式结果并输出
execute(express);
System.out.println("\r\n输入一个合法中缀表达式:");
}
}private static void handle(String nextLine, List express) {
Stack opt = new Stack<>();
// 保存操作符
int index = 0;
while (index < nextLine.length()) {
char c = nextLine.charAt(index);
if (c == '-' && (index == 0 || getPower(nextLine.charAt(index -1)) == 10)) {// 含负数算式:-2*5, 转为: 0-2*5
express.add(String.valueOf('0'));
}
if (c >= '0' && c <= '9') {// 一或多个连续数字
StringBuilder tempSpace = new StringBuilder().append(c);
while (index < nextLine.length() - 1 && (c = nextLine.charAt(index + 1)) >= '0' && c <= '9') {
tempSpace.append(c);
++index;
}
express.add(tempSpace.toString());
++index;
} else {
if (opt.isEmpty()) {
opt.push(c);
} else {
int power_c = getPower(c);
int power_top = getPower(opt.peek());
if (power_top == 10) {// 左括号
opt.push(c);
} else if (power_c == -10) {
while (!opt.isEmpty() && 10 != getPower(opt.peek())) {// 右括号,弹出所有操作符,直到遇到左括号为止
express.add(String.valueOf(opt.pop()));
}
if (!opt.isEmpty() && getPower(opt.peek()) == 10) opt.pop();
// 弹出与之配对左括号
} else {// 四则运算符
if (power_top >= power_c) { // 栈顶优先级大于或等于当前位时, 弹出栈内元素直至遇到一个优先级相等的为止
while (!opt.isEmpty() && getPower(opt.peek()) < 10&& getPower(opt.peek()) >= power_c ) {
power_top = getPower(opt.peek());
express.add(String.valueOf(opt.pop()));
if (power_top == power_c) break;
}
}
opt.push(c);
}
}
++index;
}
}
while (!opt.isEmpty()) {
if (getPower(opt.peek()) != 10 && getPower(opt.peek()) != -10)
express.add(String.valueOf(opt.pop()));
}
}private static void execute(List express) {
int index = 0;
Stack temp = new Stack<>();
while (index < express.size()) {
String c = express.get(index);
char currentOpt = c.charAt(0);
if (c.length() > 1 ||currentOpt >= '0' && currentOpt <= '9')
temp.push(Integer.parseInt(c));
else {
int right = temp.pop();
int left = temp.pop();
if (currentOpt == '+') {
temp.push(left + right);
} else if (currentOpt == '-') {
temp.push(left - right);
} else if (currentOpt == '*') {
temp.push(left * right);
} else if (currentOpt == '/') {
temp.push(left / right);
}
}
++index;
}
System.out.println("计算结果:" + temp.pop());
}public static int getPower(char c) {
if (c == '{' || c == '[' || c == '(') {
return 10;
} else if (c == '*' || c == '/') {
return 3;
} else if (c == '+' || c == '-') {
return 1;
} else if (c == ')' || c == ']' || c == '}') {
return -10;
}
return Integer.MIN_VALUE;
}}
- 部分测试用例:
3*5+8-0*3-6+0+0 5-3+9*6*(6-10-2)# 连续数字 3-10+(0+(10+5+3)-10)# 连续数字 3+2*{1+2*[-4/(8-6)+7]} # 含负数 3+2*{1+2*[4/(8-6)+7]}
- 输出
文章图片
推荐阅读
- 大数据|spark sql 创建rdd以及DataFrame和DataSet互转
- git|GIT----玩转Git
- 玩转git版本控制软件
- Spring|Spring JPA的实体属性类型转换器并反序列化工具类详解
- 基于Java解决华为机试实现整数与IP地址间的转换
- 数据分析|数据分析之pandas读写文件【to_csv,read_csv】及Numpy之间的转换
- 在CUDA C/C++中如何衡量代码性能
- MySQL索引失效之隐式转换的问题
- php不兼容_php不兼容ie
- LeetCode226 翻转二叉树