数据结构与算法中缀表达式转后缀表达式以及后缀表达式的计算
Posted GHR
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法中缀表达式转后缀表达式以及后缀表达式的计算相关的知识,希望对你有一定的参考价值。
中缀表达式转后缀表达式
方式一
步骤
1️⃣ 如果遇到操作数,我们就直接将其输出。
2️⃣ 如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
3️⃣ 如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4️⃣ 如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)(或发现最近的左括号)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。
5️⃣ 如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
代码实现
package demo03;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
public class InfixToPostfixExpression {
private char[] expression;
private Deque<Character> stack;
private ArrayList<Character> list; // 保存答案
public InfixToPostfixExpression(char[] ex) {
this.expression = ex;
stack = new ArrayDeque<>();
list = new ArrayList<>();
}
public ArrayList process() {
for (char c : expression) {
if (isOperand(c)) { //如果是操作数,入集合
list.add(c);
}
else if (isBracket(c)) { // 如果是括号
if (isLeftBracket(c)) { // 如果是左括号,入栈
stack.addLast(c);
} else { // 如果是右括号
while (!stack.isEmpty() && stack.peekLast() != \'(\') { // 一直弹出栈中元素知道遇到左括号(左括号也要但还没弹出)
list.add(stack.removeLast());
}
if (!stack.isEmpty()) stack.removeLast(); //移除栈中匹配的左括号
}
} else if (isOperator(c)) { // 如果 c 是操作符
if (stack.isEmpty()) { // 如果栈空,则入栈
stack.addLast(c);
}
else {
// 计算优先值(0:相等,-1:c优先值低于栈顶,1:c优先值大于栈顶)
int priority = priority(c) - priority(stack.peekLast());
if (priority < 0) { //遇到优先度低的,一直弹出来(直到遇到左括号)
while (!stack.isEmpty() && !isLeftBracket(stack.peekLast())) {
list.add(stack.removeLast());
}
}
stack.addLast(c); // 最后 c 入栈
}
}
}
while (!stack.isEmpty()) { // 栈中剩余元素都弹出并入集合
list.add(stack.removeLast());
}
return list;
}
// 判断是否是操作数
private boolean isOperand(char c) {
return !(isOperator(c) || isBracket(c));
}
// 计算优先值
private int priority(char c) {
if (c == \'+\' || c == \'-\') return 0;
else return 1; //if (c == \'*\' || c == \'/\')
}
// 判断是否是左括号
private boolean isLeftBracket(char c) {
return c == \'(\';
}
// 判断是否是右括号
private boolean isRightBracket(char c) {
return c == \')\';
}
// 判断是否是操作符
public boolean isOperator(char c) {
return c == \'+\' || c == \'-\' || c == \'*\' || c == \'/\';
}
// 判断是否是括号
public boolean isBracket(char c) {
return c == \'(\' || c == \')\';
}
}
测试
public static void main(String[] args) {
String ex = "a + b * c + (d * e + f)*g";
ex = ex.trim().replace(" ", "");
char[] e = ex.toCharArray();
InfixToPostfixExpression expression = new InfixToPostfixExpression(e);
ArrayList process = expression.process();
System.out.println(process.toString());
// 输出:[a, b, c, *, +, d, e, *, f, +, g, *, +]
}
方式二
1️⃣ 先按照运算符的优先级对中缀表达式加括号,变成((a + (b * c)) + (((d * e) + f) * g ))
2️⃣ 将运算符移到括号的后面,变成((a(bc) * )+(((de) * f) + g) * ) +
3️⃣ 去掉括号,得到 abc *+ de * f + g *+
后缀表达式的计算
后缀表达式也叫逆波兰表达式。
逆波兰表达式严格遵循「从左到右」的运算。计算逆波兰表达式的值时,使用一个栈存储操作数,从左到右遍历逆波兰表达式,进行如下操作:
如果遇到操作数,则将操作数入栈;
如果遇到运算符,则将两个操作数出栈,其中先出栈的是右操作数,后出栈的是左操作数,使用运算符对两个操作数进行运算,将运算得到的新操作数入栈。
整个逆波兰表达式遍历完毕之后,栈内只有一个元素,该元素即为逆波兰表达式的值。
代码
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<>();
int n = tokens.length;
for(int i = 0;i<n;i++){
if(isNum(tokens[i])){
stack.push(Integer.parseInt(tokens[i]));
}else{
int b = stack.pop();
int a = stack.pop();
switch(tokens[i]){
case "+":{
stack.push(a+b);
break;
}
case "-":{
stack.push(a-b);
break;
}
case "*":{
stack.push(a*b);
break;
}
case "/":{
stack.push(a/b);
break;
}
}
}
}
return stack.pop();
}
public boolean isNum(String s){
return !(("+".equals(s))||("-".equals(s))||("*".equals(s))||("/".equals(s)));
}
}
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:
该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
以上是关于数据结构与算法中缀表达式转后缀表达式以及后缀表达式的计算的主要内容,如果未能解决你的问题,请参考以下文章