数据结构与算法之栈

我就是我 2021-12-09 23:31 444阅读 0赞

前言

在前面几篇我们有讲到数组,链表等数据结构,这些都是存储数据的最基本的结构。而本篇文章讲解的则是利用算法和数据结构来实现一些小工具,来解决现实中某种需求。它就是栈。

什么是栈?

栈(stack) 是一种数据结构,是一个先入后出(Filo-First In Last Out) 的有序列表,只能在一端进行插入和删除操作的特殊线性表。允许插入的一端和删除的一端,为变化的一端,称为 栈顶(top),另一端为固定的一端,称为 栈底(bottom)
它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。

出栈(pop)和入栈(push)示意图

在这里插入图片描述
在这里插入图片描述

实现一个简单的栈

由于栈是一个有序列表,我们可以使用数组来实现一个栈。

代码示例:

  1. public class ArrayStack {
  2. private int[] dataArray; // 存储栈数据的数组
  3. private int maxSize; // 栈的最大长度
  4. private int top; // 指向栈顶部的指针
  5. public ArrayStack(int maxSize){
  6. this.maxSize = maxSize;
  7. this.dataArray = new int[maxSize];
  8. this.top = -1;
  9. }
  10. /**
  11. * 判断栈是否为空
  12. *
  13. * @return
  14. */
  15. public boolean isEmpty(){
  16. return top == -1;
  17. }
  18. /**
  19. * 判断栈是否满了
  20. *
  21. * @return
  22. */
  23. public boolean isFull() {
  24. return top == maxSize - 1;
  25. }
  26. /**
  27. * 入栈
  28. *
  29. * @param value
  30. */
  31. public void push(int value) {
  32. if (!this.isFull()) {
  33. dataArray[++top] = value;
  34. }
  35. }
  36. /**
  37. * 出栈
  38. *
  39. * @return
  40. */
  41. public int pop() {
  42. if (this.isEmpty()) {
  43. throw new RuntimeException("stack is empty");
  44. }
  45. return dataArray[top--];
  46. }
  47. /**
  48. * 获取栈顶部数据
  49. *
  50. * @return
  51. */
  52. public int peek(){
  53. return dataArray[top];
  54. }
  55. }

测试:

  1. public class ArrayStackTest {
  2. public static void main(String[] args) {
  3. ArrayStack arrayStack = new ArrayStack(5);
  4. arrayStack.push(1);
  5. arrayStack.push(2);
  6. arrayStack.push(3);
  7. arrayStack.push(4);
  8. arrayStack.push(5);
  9. System.out.println("stack peek:" + arrayStack.peek());
  10. while (!arrayStack.isEmpty()) {
  11. System.out.printf("[%d]", arrayStack.pop());
  12. }
  13. }
  14. }

输出结果:

  1. stack peek5
  2. [5][4][3][2][1]

上述代码内部定义了一个数组(dataArray),用来存储栈的数据,maxSize表示栈的最大容量, top是指向栈顶部的指针,初始化时为-1
构造方法传入一个参数:maxSize,用来指定栈的最大容量来创建一个新的栈,push()方法是向栈中放入元素,每放一个top+1,使它指向原顶端数据项上面的一个位置,并在这个位置上存储一个数据。pop()方法返回top变量指向的元素,然后将top变量减一,便实现了数据出栈。

利用栈实现综合计算器

实现思路:

  1. 通过一个 index 值(索引),来遍历我们的计算表达式
  2. 当遍历的当前值是数字的话, 直接放入数据栈中
  3. 当遍历的当前值是字符的话, 就分如下情况
    3.1 如果发现当前的符号栈为空,就直接入栈
    3.2 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中取出两个数,在从符号栈中取出一个符号,进行运算,将得到的结果,入数据栈,然后将当前的操作符入符号栈, 如果当前的操作符的优先级大于栈中的操作符, 就直接入符号栈.
  4. 当表达式扫描完毕,就顺序的从 数栈和符号栈中pop出相应的数和符号,并进行计算
  5. 最后在数栈只有一个数字,就是表达式的结果

代码实现:

  1. public class Calculator {
  2. public static void main(String[] args) {
  3. ArrayStack numberStack = new ArrayStack(10); // 数据栈
  4. ArrayStack operatorStack = new ArrayStack(10); // 运算符栈
  5. String expression = "6*3*9-8+5-7"; // 运算表达式
  6. // 定义相关临时辅助变量
  7. int index = 0;
  8. int num1 = 0;
  9. int num2 = 0;
  10. int oper = 0;
  11. int res = 0;
  12. char ch = ' ';
  13. String keepNum = "";
  14. while (true) {
  15. // 遍历依次得到表达式中的每一个字符
  16. ch = expression.substring(index, index + 1).charAt(0);
  17. // 判断ch是什么
  18. if (Calculator.isOperator(ch)) {// 如果是运算符
  19. // 判断当前运算符栈是否为空
  20. if (!operatorStack.isEmpty()) {
  21. // 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符, 就需要从数栈中取出两个数,在从符号栈中取出一个符号,进行运算,
  22. // 将得到的结果,入数据栈,然后将当前的操作符入符号栈
  23. if (Calculator.getPriority(ch) <= Calculator.getPriority(operatorStack.peek())) {
  24. num1 = numberStack.pop();
  25. num2 = numberStack.pop();
  26. oper = operatorStack.pop();
  27. // 进行计算
  28. res = Calculator.cal(num1, num2, oper);
  29. // 将计算得到的结果放入数据栈
  30. numberStack.push(res);
  31. // 将当前的运算符放入运算符栈
  32. operatorStack.push(ch);
  33. } else {
  34. // 如果当前的运算符的优先级大于栈中的运算符,就直接放入运算符栈
  35. operatorStack.push(ch);
  36. }
  37. } else {
  38. // 直接入运算符栈
  39. operatorStack.push(ch); // 1 + 3
  40. }
  41. } else { // 如果是数字直接入数据栈
  42. // 处理多位数
  43. keepNum += ch;
  44. // 判断是否是表达式最后一个字符,如果是,直接入栈
  45. if (index == expression.length() - 1) {
  46. numberStack.push(Integer.parseInt(keepNum));
  47. } else {
  48. // 判断下一个字符是不是数字,如果是数字,就继续遍历,如果是运算符,就直接入栈
  49. if (Calculator.isOperator(expression.substring(index + 1, index + 2).charAt(0))) {
  50. numberStack.push(Integer.parseInt(keepNum));
  51. // 清空
  52. keepNum = "";
  53. }
  54. }
  55. }
  56. // 让index+1,判断表达式是否遍历完了
  57. index++;
  58. if (index >= expression.length()) {
  59. break;
  60. }
  61. }
  62. // 当表达式遍历完了之后,就顺序从数据栈和运算符栈中取出相应的数字和运算符进行计算
  63. while (true) {
  64. // 如果运算符栈为空,则代表计算到了最后的结果,数据栈中就只有一个结果数据了
  65. if (operatorStack.isEmpty()) {
  66. break;
  67. }
  68. num1 = numberStack.pop();
  69. num2 = numberStack.pop();
  70. oper = operatorStack.pop();
  71. // 计算结果
  72. res = Calculator.cal(num1, num2, oper);
  73. numberStack.push(res);//ÈëÕ»
  74. }
  75. System.out.printf("运算表达式 %s = %d", expression, numberStack.pop());
  76. }
  77. /**
  78. * 返回运算符的优先级
  79. *
  80. * @param operator 运算符
  81. * @return
  82. */
  83. public static int getPriority(int operator) {
  84. if (operator == '*' || operator == '/') {
  85. return 1;
  86. } else if (operator == '+' || operator == '-') {
  87. return 0;
  88. } else {
  89. return -1; // 目前只支持 +, - , * , /
  90. }
  91. }
  92. /**
  93. * 是否是运算符判断
  94. *
  95. * @param val
  96. * @return
  97. */
  98. public static boolean isOperator(char val) {
  99. return val == '+' || val == '-' || val == '*' || val == '/';
  100. }
  101. /**
  102. * 计算
  103. *
  104. * @param num1 数据一
  105. * @param num2 数据二
  106. * @param oper 运算符
  107. * @return
  108. */
  109. public static int cal(int num1, int num2, int oper) {
  110. int result = 0;
  111. switch (oper) {
  112. case '+':
  113. result = num1 + num2;
  114. break;
  115. case '-':
  116. result = num2 - num1;
  117. break;
  118. case '*':
  119. result = num1 * num2;
  120. break;
  121. case '/':
  122. result = num2 / num1;
  123. break;
  124. default:
  125. break;
  126. }
  127. return result;
  128. }
  129. }

测试结果:

  1. 运算表达式 6*3*9-8+5-7 = 152

发表评论

表情:
评论列表 (有 0 条评论,444人围观)

还没有评论,来说两句吧...

相关阅读

    相关 数据结构算法-

    什么是栈 栈又称为堆栈,是一种运算受限定表。说是限定表是由于对于元素的入栈和出栈都在表末尾进行,换言之就是先进后出,其本质就是对表尾部元素进行操作。在计算机系统中,栈是具有

    相关 数据结构算法

    数据结构与算法 栈 一、简述       栈是一种只能在一端进行插入或删除操作的线性表。进行插入、删除的一端称为栈顶,栈顶的当前位置是动态的,由一个称为栈顶指针的位置指

    相关 数据结构算法

    前言 在前面几篇我们有讲到数组,链表等数据结构,这些都是存储数据的最基本的结构。而本篇文章讲解的则是利用算法和数据结构来实现一些小工具,来解决现实中某种需求。它就是栈。