当前位置:   article > 正文

栈和队列的操作和应用_栈和队列的应用

栈和队列的应用

本节内容

1.栈和队列的特性

 栈:进先出

•栈:受限制的线性表,只允许从表的一端操作。这端称为栈顶,另一端为

•压入元素(push):往栈顶新增一个元素,新元素成为新栈顶。

•弹出元素(pop):移除栈顶元素,原栈顶的元素成为新栈顶/或栈变成空栈

•图片表示进出栈结果:

 *key1:栈是一种先进后出的数据结构,pop和push操作仅在栈顶进行

 队列:进先出

•队列:受限制的线性表,只允许从表的两端操作,一端是队首,一端是队尾。

•入队(enqueue):往队尾新增一个元素,新元素成为新队尾

•出队(dequeue):移出队首元素,下一个元素成为新队首/或队列变为空

•图文演示过程:

 2.栈和递归

 •栈后进先出的特点天然地和程序中函数调用关系相吻合

•程序执行时,在函数A中执行到调用另一个函数B的语句时,会发生什么?

        立刻进入被调函数B执行其代码,完成后返回到A的下一行继续执行A的剩余代码

•因此在操作系统执行代码时,函数间的调用-返回关系正是通过调用栈来维护

•函数的递归调用本质也是一个栈型调用,因此可以利用栈将一个递归函数改写为完全等价的非递归函数,避免了操作系统层面的调用栈开销。

 3.栈和队列的应用

栈的应用:括号匹配

•目的:判断一个字符串你中括号是否——匹配

•为什么可以用栈来解决这个问题?

•当遇到左括号时,我希望能立刻遇到它的另一半,但如果接着又遇到了一个左括号,那它的需求比我更紧迫,我需要处理来的这个左括号

•后来的需要先满足->后进先出问题->用栈解决

栈的应用

•表达式求值,如1+2*3

•进制转换

•非递归的深度优先遍历(DFS)

队列的应用:循环队列(循环队列基于顺序序列)

•你会怎样实现一个顺序序列?

'假溢出'现象:底层顺序表前部的可用空间无法再利用上了

•解决方法:循环队列

 4.代码实现

顺序栈实现

•顺序栈的底层是一个数组,低地址为栈底,高地址为栈顶,只能在栈顶操作

  1. /*(顺序)栈*/
  2. //栈数据结构定义
  3. #define MAX_SIZE 10
  4. typedef struct{
  5. Student *data;
  6. int size;
  7. }Stack;
  1. //往栈顶压入一个元素
  2. bool Push(Stack &stk,const Student &s){
  3. if (stk.size==MAX_SIZE){
  4. return false;
  5. }
  6. int newTop=stk.size;
  7. stk.data[newTop]=s;
  8. stk.size++;
  9. return true;
  10. }
  1. //弹出栈顶元素
  2. bool Pop(Stack &stk){
  3. if(stk.size==0){
  4. return false;}
  5. stk.size--;
  6. return true;
  7. }

*key1:顺序栈的底层是一个数组空间,并通过维护当前栈大小实现栈

*key2:顺序栈的当前栈顶元素下标和栈大小是top=size-1的关系

1.设Stack是顺序栈的一种实现,在(a)处应填入的代码为:___________.(stk.size--)

struct Stack{

        Elem data[MAX_SIZE];

        int size=0;

};

bool Pop(Stack &s){

        if (stk.size==0)return false;

        ___(a)____;

        return true;

}

循环队列实现

•循环队列的底层是一个数组,通过维护队头和队尾在此数组中的下标来实现

  1. /*循环队列*/
  2. //循环队列数据结构
  3. #define M 10
  4. typedef struct{
  5. Student data[M];
  6. int front;
  7. int back;//bcak表示队尾的下一个空位
  8. }CQueue;//c=Circulative
  1. //求循环队列元素个数
  2. int GetSize(CQueue &queue){
  3. int size=(queue.back-queue.front+M)%M;
  4. return size;
  5. }

*key1:循环队列的容量是MAX_SIZE-1

*key2:循环队列当前元素数量计算

1.假设一循环队列的底层数组为array[M],我们约定f表示为当前队首元素,b为当前队尾元素的后

一个元素,则当前队列内元素个数为()

A.b-f                B.(b-f+M)%M

C.b-f+M           D.(f-b+M)%M

分析:做循环队列题一定要把底层数组画出来模拟!

第一种情况:

 第二种情况:

 M=8,蓝色表示队列元素。

分析:对于第一种情况直接=b-f,第二种情况等于b-f+M

统一一下答案:由于b-f>0,所以加上M再对M取余正好消去M。第二个由于b-f<0,b-f+M<M

所以对M取余不起作用。总结答案选择为B选项

循环队列实现

•循环队列的底层是一个数组,通过维护队头和队尾在此数组中的下标来实现

  1. //循环队列入列
  2. bool Enqueue_CQ(CQueue &queue,const Student &s){
  3. int newBack=(queue.back+1)%M;
  4. if(newBack==queue.front){
  5. return false;//头尾相接表示队列满了}
  6. queue.data[queue.back]=s;//放入队尾
  7. queue.back=newBack;
  8. return true;
  9. }
  1. //循环队列出列
  2. bool Dequeue_CQ(CQueue &queue){
  3. if (queue.front==queue.back){
  4. return false;//头尾重合表示队列为空
  5. } queue.front=(queue.front+1)%M;
  6. return true;
  7. }

*key3:循环队列判满条件为(back+1)%MAX_SIZE==front ''首尾相接''

*key4:循环队列判空条件为back==front                                     ''首尾重合''

1.(a)处应填入的代码为:______________.(queue.front ==queue.back)

bool Dequeue_CQ(CQueue &queue){

        if (___(a)____)

                return false;//头尾重合表示队列为空

}queue.front=(queue.front +1)%queue.capacity;

return true;                

}

练习:

 

 

 

完整代码: 

  1. /*
  2. Ch3 栈和队列
  3. */
  4. // 实例数据元素:学生
  5. typedef struct {
  6. char id[10];
  7. int age;
  8. double score;
  9. } Student;
  10. /* (顺序)栈 */
  11. // 栈数据结构定义
  12. #define MAX_SIZE 10
  13. typedef struct {
  14. Student *data;
  15. int size;
  16. } Stack;
  17. // 初始化栈
  18. Stack Create() {
  19. Stack stk;
  20. stk.data = new Student[MAX_SIZE];
  21. stk.size = 0;
  22. return stk;
  23. }
  24. // 获取栈顶元素
  25. bool Top(Stack &stk, Student &res) {
  26. if (stk.size == 0) {
  27. return false;
  28. }
  29. int top = stk.size - 1;
  30. res = stk.data[top];
  31. return true;
  32. }
  33. // 弹出栈顶元素
  34. bool Pop(Stack &stk) {
  35. if (stk.size == 0) {
  36. return false;
  37. }
  38. stk.size--;
  39. return true;
  40. }
  41. // 往栈顶压入一个元素
  42. bool Push(Stack &stk, const Student &s) {
  43. if (stk.size == MAX_SIZE) {
  44. return false;
  45. }
  46. int newTop = stk.size;
  47. stk.data[newTop] = s;
  48. stk.size++;
  49. return true;
  50. }
  51. /* 栈的应用:括号匹配 */
  52. #include <stack>
  53. #include <string>
  54. bool IsParenthesesMatch(std::string s) {
  55. std::stack<char> stk;
  56. for (int i = 0; i < s.length(); ++i) {
  57. switch (s[i]) {
  58. case '(':
  59. case '[':
  60. case '{':
  61. stk.push(s[i]);
  62. break;
  63. case ')':
  64. if (stk.empty() || stk.top() != '(') {
  65. return false;
  66. }
  67. stk.pop();
  68. break;
  69. case ']':
  70. if (stk.empty() || stk.top() != '[') {
  71. return false;
  72. }
  73. stk.pop();
  74. break;
  75. case '}':
  76. if (stk.empty() || stk.top() != '}') {
  77. return false;
  78. }
  79. stk.pop();
  80. break;
  81. }
  82. }
  83. return stk.empty();
  84. }
  85. /* 循环队列 */
  86. // 循环队列数据结构
  87. #define M 10
  88. typedef struct {
  89. Student data[M];
  90. int front;
  91. int back; // back表示队尾的下一个空位
  92. } CQueue; // C = Circulative
  93. // 循环队列入队
  94. bool Enqueue_CQ(CQueue &queue, const Student &s) {
  95. int newBack = (queue.back + 1) % M;
  96. if (newBack == queue.front) {
  97. return false; // 头尾相接表示队列满了
  98. }
  99. queue.data[queue.back] = s; // 放入队尾
  100. queue.back = newBack; // 移动back
  101. return true;
  102. }
  103. // 循环队列出队
  104. bool Dequeue_CQ(CQueue &queue) {
  105. if (queue.front == queue.back) {
  106. return false; // 头尾重合表示队列为空
  107. }
  108. queue.front = (queue.front + 1) % M;
  109. return true;
  110. }
  111. // 求循环队列元素个数
  112. int GetSize(CQueue &queue) {
  113. int size = (queue.back - queue.front + M) % M;
  114. return size;
  115. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/869041
推荐阅读
相关标签
  

闽ICP备14008679号