栈与逆波兰表达式
1.背景
栈经常被面试到
'6+8-(4X5)-2'如何解析并运算
逆波兰表达式
2.使用栈实现简单的计算表达式

package com.ldp.structure.demo01; import org.junit.Test; import java.util.Scanner; /** * 基于数组的栈 */ public class Test04ArrayStack { /** * 基于数组的栈演示 * * @param args */ public static void main(String[] args) { ArrayStack arrayStack = new ArrayStack(3); Scanner scanner = new Scanner(System.in); String key = ""; boolean flag = true; while (flag) { System.out.println("(s)show查看队列"); System.out.println("(p)push添加一个元素"); System.out.println("(o)pop获取一个元素"); System.out.println("(e)exit退出系统"); key = scanner.next(); switch (key) { case "s": arrayStack.show(); break; case "p": System.out.println("请输入一个数字:"); arrayStack.push(Integer.valueOf(scanner.next())); break; case "o": try { System.out.println(arrayStack.pop()); } catch (Exception e) { System.out.println(e.getMessage()); } break; case "e": System.out.println("退出系统"); flag = false; break; default: System.out.println("输入错误"); } } } /** * 基于栈实现解析运算表达式如: 3+9/3 = 6 */ @Test public void test01() { // String expression = "3+2*5-1"; // 12 // String expression = "3+9/3"; // 6 // String expression = "3+9/3-2+8/2-1"; // 7 3+3-2+4-1=7 String expression = "3+2*6-2"; // 13 // 定义数栈 ArrayStack numStack = new ArrayStack(10); // 定义符号栈 ArrayStack operationStack = new ArrayStack(10); // 下标 int index = 0; // 这次计算乘法和除法 while (index < expression.length()) { String str = expression.substring(index, index + 1); // 入栈 if (OperationUtil.isOperation(str)) { // 检查优先级,如果是乘或者除就执行运算 if (OperationUtil.priorityNum(str) == 1) { // 取出下一个数字 index++; String str2Num = expression.substring(index, index + 1); // 取出数字栈中的第一个数字 String str1Num = (String) numStack.pop(); // 执行运算 int calculation = OperationUtil.calculation(Integer.valueOf(str1Num), str, Integer.valueOf(str2Num)); // 将计算的结果放入数字栈中,以字符串的形式放入 numStack.push(String.valueOf(calculation)); } else { // 加法 减法先放入栈中 operationStack.push(str); } } else { numStack.push(str); } // 向下移动一个角标 index++; } // 计算加法 和 减法 // 倒序 numStack = numStack.resv(numStack); operationStack = operationStack.resv(operationStack); while (!operationStack.isEmpty()) { String num1 = (String) numStack.pop(); String num2 = (String) numStack.pop(); String operation = (String) operationStack.pop(); // 应从栈里面取出来的是最新的数据,因此应交换计算 int calculation = OperationUtil.calculation(Integer.valueOf(num1), operation, Integer.valueOf(num2)); // 将计算结果放入数字栈中 numStack.push(String.valueOf(calculation)); } System.out.println("测试完成....结果:" + numStack.pop()); } } class ArrayStack { Object[] data; int top = -1; int size; public ArrayStack(int size) { this.size = size; this.data = new Object[size]; } // 栈满 public boolean isFull() { return top == size - 1; } // 空栈 public boolean isEmpty() { return top == -1; } // 入栈 public void push(Object i) { if (isFull()) { System.out.println("栈栈满....."); } else { top++; data[top] = i; } } // 出栈 public Object pop() { if (isEmpty()) { throw new RuntimeException("栈中无数据..."); } Object n = data[top]; top--; return n; } // 栈倒序 public ArrayStack resv(ArrayStack stack) { ArrayStack arrayStackNew = new ArrayStack(stack.size); while (!stack.isEmpty()) { arrayStackNew.push(stack.pop()); } return arrayStackNew; } // 显示栈的情况(遍历) public void show() { if (isEmpty()) { System.out.println("栈中无数据...."); return; } for (int i = top; i >= 0; i--) { System.out.print(data[i] + " \t"); } System.out.println(); } } class OperationUtil { // 判定是否为符号 public static boolean isOperation(String str) { if (str == null) { return false; } if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) { return true; } return false; } // 判定优先级,值越大越优先, + - 为0, * / 为1 public static int priorityNum(String str) { if (str.equals("+") || str.equals("-")) { return 0; } else if (str.equals("*") || str.equals("/")) { return 1; } else { return -1; } } /** * 计算 * * @param num1 第一个运算数字 * @param operation 运算符 * @param num2 第二个运算数字 * @return */ public static int calculation(int num1, String operation, int num2) { int result = 0; if ("+".equals(operation)) { result = num1 + num2; } else if ("-".equals(operation)) { result = num1 - num2; } else if ("*".equals(operation)) { result = num1 * num2; } else if ("/".equals(operation)) { result = num1 / num2; } else { throw new RuntimeException("运算符未知:" + operation); } return result; } }
3.使用逆波兰表达式实现带有括号的表达式
3.1.中缀表达式转逆波兰表达式思路
3.2.逆波兰表达式计算
package com.ldp.structure.demo01; import org.junit.Test; import java.util.LinkedList; import java.util.List; import java.util.Stack; /** * 后缀表达式(逆波兰表达式) */ public class Test06Suffix { /** * 中缀表达式转后缀表达式 */ @Test public void testInfillToSuffix() { String expression = "6+8-(4*5)-2";// System.out.println("中缀表达式:" + expression); List<String> list = infillToSuffix(expression); System.out.println("后缀表达式:" + list); int count = suffixCount(list); System.out.println("后缀表达式计算出来的结果: " + expression + "=" + count); } /** * 后缀表达式执行运算 */ @Test public void testSuffixCount() { String expression = "6+8-(4*5)-2"; List<String> list = infillToSuffix(expression); System.out.println(list); } /** * 是数字就直接入栈,是符号就弹出2个数进行运算,最后栈你只会剩下一个数,就是结果 * * @param list * @return */ public int suffixCount(List<String> list) { Stack<String> stack = new Stack<>(); for (String str : list) { if (isOperation(str)) { String number2 = stack.pop(); String number1 = stack.pop(); int calculation = calculation(Integer.valueOf(number1), str, Integer.valueOf(number2)); stack.push("" + calculation); } else { stack.push(str); } } return Integer.valueOf(stack.pop()); } /** * 中缀表达式转为后缀表达式,使用ArrayList存放 */ public List<String> infillToSuffix(String expression) { // 定义一个存放符号的临时栈stack1 Stack<String> stack1 = new Stack<>(); // 定义一个存放数字和符号的栈stack2 Stack<String> stack2 = new Stack<>(); // 接收字符的临时变量 String strTemp = ""; int index = 0; while (index < expression.length()) { String str = expression.substring(index, index + 1); if ("(".equals(str)) { // 直接入栈 stack1.push(str); index++; } else if (")".equals(str)) { // 将stack1中的符号弹出到stack2直到 stack1中弹出"("为止,即丢弃一对括号 while (true) { String item = stack1.pop(); if ("(".equals(item)) { index++; break; } stack2.push(item); } } else if (isOperation(str)) { // 运算符号 while (true) { // 如果stack1栈顶为空 或者不是 运算符 直接入栈 if (stack1.isEmpty() || !isOperation(stack1.peek())) { stack1.push(str); index++; break; } else if (priorityNum(str) > priorityNum(stack1.peek())) { // 比栈顶优先级高直接入栈 stack1.push(str); index++; break; } else { // 将stack1栈顶运算符弹出到stack2 stack2.push(stack1.pop()); } } } else { // 数字 stack2.push(str); index++; } } // 将stack1中的运算符弹出到stack2 while (!stack1.isEmpty()) { stack2.push(stack1.pop()); } // 倒序放入list中 LinkedList<String> list = new LinkedList(); while (!stack2.isEmpty()) { list.addFirst(stack2.pop()); } return list; } // 当前运算符低于栈顶运算符时,将栈顶运算符弹出到stack2 public void handleOperation() { } // 判定是否为符号 public static boolean isOperation(String str) { if (str == null) { return false; } if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) { return true; } return false; } // 判定优先级,值越大越优先, + - 为0, * / 为1 public static int priorityNum(String str) { if (str.equals("+") || str.equals("-")) { return 0; } else if (str.equals("*") || str.equals("/")) { return 1; } else { return -1; } } /** * 计算 * * @param num1 第一个运算数字 * @param operation 运算符 * @param num2 第二个运算数字 * @return */ public static int calculation(int num1, String operation, int num2) { int result = 0; if ("+".equals(operation)) { result = num1 + num2; } else if ("-".equals(operation)) { result = num1 - num2; } else if ("*".equals(operation)) { result = num1 * num2; } else if ("/".equals(operation)) { result = num1 / num2; } else { throw new RuntimeException("运算符未知:" + operation); } return result; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!