中缀表达式转后缀表达式
中缀表达式
- 就是我们平常所使用的计算方式就叫中缀表达式,即运算符在中间,运算符的左右各有一个操作数
- 例如:
1 + 2和2 * 3- 但中缀表达式不容易被计算机解析
后缀表达式
- 后缀表达式就是运算符在最右边,两个操作数都在运算符的左边
- 例如:把
a + b写成a b +,就是把中缀表达式转成了后缀表达式技巧:
- 首先以乘除加减的顺序加上括号。
- 然后由里向外或者由外向里将运算符挪到对应的括号外面。
- 去掉括号,就得到了后缀表达式。
不可能的出栈顺序
如何把(2+4)* 3 - 1 这个中缀表达式转为后缀表达式?
1、第一步:加括号,根据运算的优先级加上对应的括号即可~ (((2+4)* 3 )- 1) 2、第二步:移运算符,将运算符移到右边第一个括号的外面 (((24)+ 3 )* 1)- 3、第三步:去括号, 24+ 3 * 1- 4、第四步:使用栈的思想计算出来
- 2、4 是操作数就入栈
- 遇到 运算符 了就出栈,第一个出栈的数字放运算符的右边,第二个出栈的放运算符的左边,然后将计算出的结果再入栈
- 如此循环即可得出答案~
计算流程图
经典题目
题目1
题目分析:
- 先让第一个元素入栈
- 每次入栈之后就判断栈顶元素和 popA 数组 j 下标的元素是否相等,相等则栈顶元素弹出,数组 popA 的指针 j 也往后走一步。
- 走完循环看栈是否为空
代码
public boolean IsPopOrder(int [] pushA,int [] popA) {
if (pushA == null || popA == null) return false;
Stack<Integer> stack = new Stack<>();
int j = 0;
for (int i = 0; i < pushA.length; i++) {
stack.push(pushA[i]);
while (!stack.isEmpty() && stack.peek() == popA[j] && j < popA.length) {
stack.pop();
j++;
}
}
return stack.isEmpty();
}
题目2
代码
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < tokens.length; i++) {
String ch = tokens[i];
if (!check(ch)) {
stack.push(Integer.parseInt(ch));
} else {
int num2 = stack.pop();
int num1 = stack.pop();
switch (ch) {
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
}
}
}
return stack.pop();
}
private boolean check(String s) {
return s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/");
}
题目3
题目分析:
总共有一下四种情况:
- 左右括号不匹配
- 左括号比右括号多
- 右括号比左括号多
- 匹配成功
代码
public boolean isValid(String s) {
if (s == null) return true;
Stack<Character> stack = new Stack<>();
for (char ch : s.toCharArray()) {
if (ch == '(' || ch == '[' || ch == '{') {
// 只要是左括号就进栈
stack.push(ch);
} else {
// 走到这就是右括号了,看是否匹配
if (stack.isEmpty()) return false;
char top = stack.peek();
if ((ch == ')' && top == '(') || (ch == ']' && top == '[') || (ch == '}' && top == '{')) {
stack.pop();// 匹配成功就弹出
} else {
// 走到这说明,左括号比右括号多
return false;
}
}
}
// 栈不为空则说明,右括号比左括号多
return stack.isEmpty();
}
题目4
题目分析:
- 准备一个普通栈和一个最小栈
- 普通栈每个元素都要入,不需要判断。最小栈就是要保证栈顶元素是普通栈中最小的那个元素
- 最小栈入栈的话,就需要每次让普通栈和最小栈比较,如果比最小栈的栈顶元素都要小,就将这个元素也入到最小栈中
- 删除普通栈中的元素的时候也需要和最小栈的栈顶元素比较,可能你要删除的就是最小值~
代码
public class MinStack {
// 普通栈
private Stack<Integer> stack;
// 最小栈,存放最小元素
private Stack<Integer> minStack;
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
//将元素val推入堆栈
public void push(int val) {
stack.push(val);
if (minStack.empty()) {
minStack.push(val);
} else {
int top = minStack.peek();
if (val <= top) {
minStack.push(val);
}
}
}
//删除堆栈顶部的元素
public void pop() {
if (stack.empty()) return;
int tmp = stack.pop();
int top = minStack.peek();
if (tmp == top) {
minStack.pop();
}
}
//获取堆栈顶部的元素
public int top() {
if (stack.empty()) return -1;
return stack.peek();
}
//获取堆栈中的最小元素
public int getMin() {
if (minStack.empty()) return -1;
return minStack.peek();
}
}