原文地址:https://blog.csdn.net/guorui_java/article/details/106193563

一、栈

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

二、栈的应用场景

1、子程序的调用

在调往子程序前,会先将下个指令的地址存放到堆栈中,直到子程序执行完后再将地址抛出,以回到原来的程序。

2、处理递归调用

和子程序的调用类似,除了村下个指令的地址外,还要存放参数,区域变量等数据。

3、表达式的转换

中缀表达式转后缀表达式

4、二叉树的遍历

5、图形的深度优先搜索法

三、栈实现综合计算器(中缀表达式)

1、思路分析

  • 通过一个index值(索引),来遍历我们的表达式
  • 如果发现是一个数字直接入数栈
  • 如果发现当前的符号栈是空,就直接入栈
  • 如果发现符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或等于栈中的操作符,就需要从数栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈,如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈。
  • 当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数和符号,并进行运算。
  • 最后在数栈中只有一个数字,就是表达式的结果。

    2、代码实例

(1)ArrayStack工具类

  1. package dataStructure.stack;
  2. public class ArrayStack {
  3. private int maxSize; // 栈的大小
  4. private int[] stack; // 数组,数组模拟栈,数据就放在该数组
  5. private int top = -1;// top表示栈顶,初始化为-1
  6. //构造器
  7. public ArrayStack(int maxSize) {
  8. this.maxSize = maxSize;
  9. stack = new int[this.maxSize];
  10. }
  11. //增加一个方法,可以返回当前栈顶的值, 但是不是真正的pop
  12. public int peek() {
  13. return stack[top];
  14. }
  15. //栈满
  16. public boolean isFull() {
  17. return top == maxSize - 1;
  18. }
  19. //栈空
  20. public boolean isEmpty() {
  21. return top == -1;
  22. }
  23. //入栈-push
  24. public void push(int value) {
  25. //先判断栈是否满
  26. if(isFull()) {
  27. System.out.println("栈满");
  28. return;
  29. }
  30. top++;
  31. stack[top] = value;
  32. }
  33. //出栈-pop, 将栈顶的数据返回
  34. public int pop() {
  35. //先判断栈是否空
  36. if(isEmpty()) {
  37. //抛出异常
  38. throw new RuntimeException("栈空,没有数据~");
  39. }
  40. int value = stack[top];
  41. top--;
  42. return value;
  43. }
  44. //显示栈的情况[遍历栈], 遍历时,需要从栈顶开始显示数据
  45. public void list() {
  46. if(isEmpty()) {
  47. System.out.println("栈空,没有数据~~");
  48. return;
  49. }
  50. //需要从栈顶开始显示数据
  51. for(int i = top; i >= 0 ; i--) {
  52. System.out.printf("stack[%d]=%d\n", i, stack[i]);
  53. }
  54. }
  55. //返回运算符的优先级,优先级是程序员来确定, 优先级使用数字表示
  56. //数字越大,则优先级就越高.
  57. public int priority(int oper) {
  58. if(oper == '*' || oper == '/'){
  59. return 1;
  60. } else if (oper == '+' || oper == '-') {
  61. return 0;
  62. } else {
  63. return -1; // 假定目前的表达式只有 +, - , * , /
  64. }
  65. }
  66. //判断是不是一个运算符
  67. public boolean isOper(char val) {
  68. return val == '+' || val == '-' || val == '*' || val == '/';
  69. }
  70. //计算方法
  71. public int cal(int num1, int num2, int oper) {
  72. int res = 0; // res 用于存放计算的结果
  73. switch (oper) {
  74. case '+':
  75. res = num1 + num2;
  76. break;
  77. case '-':
  78. res = num2 - num1;// 注意顺序
  79. break;
  80. case '*':
  81. res = num1 * num2;
  82. break;
  83. case '/':
  84. res = num2 / num1;
  85. break;
  86. default:
  87. break;
  88. }
  89. return res;
  90. }
  91. }

(2)测试类

  1. package dataStructure.stack;
  2. public class Calculator {
  3. public static void main(String[] args) {
  4. //根据前面老师思路,完成表达式的运算
  5. String expression = "100/5+2*3-1"; // 25
  6. //创建两个栈,数栈,一个符号栈
  7. ArrayStack numStack = new ArrayStack(10);
  8. ArrayStack operStack = new ArrayStack(10);
  9. //定义需要的相关变量
  10. int index = 0;//用于扫描
  11. int num1 = 0;
  12. int num2 = 0;
  13. int oper = 0;
  14. int res = 0;
  15. char ch = ' '; //将每次扫描得到char保存到ch
  16. String keepNum = ""; //用于拼接 多位数
  17. //开始while循环的扫描expression
  18. while (true) {
  19. //依次得到expression 的每一个字符
  20. ch = expression.substring(index, index + 1).charAt(0);
  21. //判断ch是什么,然后做相应的处理
  22. if (operStack.isOper(ch)) {//如果是运算符
  23. //判断当前的符号栈是否为空
  24. if (!operStack.isEmpty()) {
  25. //如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数,
  26. //在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈
  27. if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {
  28. num1 = numStack.pop();
  29. num2 = numStack.pop();
  30. oper = operStack.pop();
  31. res = numStack.cal(num1, num2, oper);
  32. //把运算的结果如数栈
  33. numStack.push(res);
  34. //然后将当前的操作符入符号栈
  35. operStack.push(ch);
  36. } else {
  37. //如果当前的操作符的优先级大于栈中的操作符, 就直接入符号栈.
  38. operStack.push(ch);
  39. }
  40. } else {
  41. //如果为空直接入符号栈..
  42. operStack.push(ch); // 1 + 3
  43. }
  44. } else { //如果是数,则直接入数栈
  45. //numStack.push(ch - 48); //? "1+3" '1' => 1
  46. //分析思路
  47. //1. 当处理多位数时,不能发现是一个数就立即入栈,因为他可能是多位数
  48. //2. 在处理数,需要向expression的表达式的index 后再看一位,如果是数就进行扫描,如果是符号才入栈
  49. //3. 因此我们需要定义一个变量 字符串,用于拼接
  50. //处理多位数
  51. keepNum += ch;
  52. //如果ch已经是expression的最后一位,就直接入栈
  53. if (index == expression.length() - 1) {
  54. numStack.push(Integer.parseInt(keepNum));
  55. } else {
  56. //判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,则入栈
  57. //注意是看后一位,不是index++
  58. if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {
  59. //如果后一位是运算符,则入栈 keepNum = "1" 或者 "123"
  60. numStack.push(Integer.parseInt(keepNum));
  61. //重要的!!!!!!, keepNum清空
  62. keepNum = "";
  63. }
  64. }
  65. }
  66. //让index + 1, 并判断是否扫描到expression最后.
  67. index++;
  68. if (index >= expression.length()) {
  69. break;
  70. }
  71. }
  72. //当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并运行.
  73. while (true) {
  74. //如果符号栈为空,则计算到最后的结果, 数栈中只有一个数字【结果】
  75. if (operStack.isEmpty()) {
  76. break;
  77. }
  78. num1 = numStack.pop();
  79. num2 = numStack.pop();
  80. oper = operStack.pop();
  81. res = numStack.cal(num1, num2, oper);
  82. numStack.push(res);//入栈
  83. }
  84. //将数栈的最后数,pop出,就是结果
  85. int res2 = numStack.pop();
  86. System.out.printf("表达式 %s = %d", expression, res2);
  87. }
  88. }

3、控制台输出

5.栈实现综合计算器 - 图1