• 栈和队列(栈和队列的实现、两个队列实现栈、两个栈实现一个队列等经典例题)


    ꧁ 大家好,我是 兔7 ,一位努力学习C++的博主~ ꧂

    ☙ 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步❧

    🚀 如有不懂,可以随时向我提问,我会全力讲解~💬

    🔥 如果感觉博主的文章还不错的话,希望大家关注、点赞、收藏三连支持一下博主哦~!👀

    🔥 你们的支持是我创作的动力!⛅

    🧸 我相信现在的努力的艰辛,都是为以后的美好最好的见证!⭐

    🧸 人的心态决定姿态!⭐

    🚀 本文章CSDN首发!✍

    目录

    0. 前言

    1. 栈

    1.1 栈的概念及结构

    1.2 栈的实现

    Stack.h

    Stack.c

    2. 队列

    2.1 队列的概念及结构

    2.2队列的实现

    Queue.h

    Queue.c

    3. 栈和队列面试题


    0. 前言

            此博客为博主以后复习的资料,所以大家放心学习,总结的很全面,每段代码都给大家发了出来,大家如果有疑问可以尝试去调试。

            大家一定要认真看图,图里的文字都是精华,好多的细节都在图中展示、写出来了,所以大家一定要仔细哦~

            感谢大家对我的支持,感谢大家的喜欢, 兔7 祝大家在学习的路上一路顺利,生活的路上顺心顺意~!

    1. 栈

    1.1 栈的概念及结构

    栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

    压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

    出栈:栈的删除操作叫做出栈。出数据也在栈顶。

    1.2 栈的实现

            栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的 代价比较小。

    Stack.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. typedef int STDataType;
    7. typedef struct Stack
    8. {
    9. STDataType* a;
    10. int top;
    11. int capacity;
    12. }Stack;
    13. void StackInit(Stack* ps);
    14. void StackDestroy(Stack* ps);
    15. void StackPush(Stack* ps, STDataType x);
    16. void StackPop(Stack* ps);
    17. STDataType StackTop(Stack* ps);
    18. bool IsEmpty(Stack* ps);
    19. int Size(Stack* ps);

    Stack.c

    1. #include "Stack.h"
    2. void StackInit(Stack* ps)
    3. {
    4. assert(ps);
    5. ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
    6. ps->top = 0;
    7. ps->capacity = 4;
    8. }
    9. void StackDestroy(Stack* ps)
    10. {
    11. assert(ps);
    12. free(ps->a);
    13. ps->a = NULL;
    14. ps->top = 0;
    15. ps->capacity = 0;
    16. }
    17. bool IsEmpty(Stack* ps)
    18. {
    19. assert(ps);
    20. return ps->top == 0;
    21. }
    22. void StackPush(Stack* ps, STDataType x)
    23. {
    24. assert(ps);
    25. if (ps->top == ps->capacity)
    26. {
    27. int newcapacity = ps->capacity * 2;
    28. STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
    29. if (tmp == NULL)
    30. {
    31. perror("StackPush error");
    32. exit(-1);
    33. }
    34. ps->a = tmp;
    35. ps->capacity = newcapacity;
    36. }
    37. ps->a[ps->top] = x;
    38. ps->top++;
    39. }
    40. void StackPop(Stack* ps)
    41. {
    42. assert(ps);
    43. assert(!IsEmpty(ps));
    44. ps->top--;
    45. }
    46. STDataType StackTop(Stack* ps)
    47. {
    48. assert(ps);
    49. assert(IsEmpty(ps));
    50. return ps->a[ps->top - 1];
    51. }
    52. int Size(Stack* ps)
    53. {
    54. return ps->top;
    55. }
    56. void Print(Stack* ps)
    57. {
    58. assert(ps);
    59. int top = ps->top - 1;
    60. while (top >= 0)
    61. {
    62. printf("%d ", ps->a[top--]);
    63. }
    64. printf("\n");
    65. }

    2. 队列

    2.1 队列的概念及结构

            队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

    2.2队列的实现

            队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

    Queue.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. typedef int QDataType;
    6. typedef struct QueueNode
    7. {
    8. struct QueueNode* next;
    9. QDataType data;
    10. }QueueNode;
    11. typedef struct Queue
    12. {
    13. QueueNode* head;
    14. QueueNode* tail;
    15. }Queue;
    16. void QueueInit(Queue* pq);
    17. void QueueDestroy(Queue* pq);
    18. void QueuePush(Queue* pq, QDataType x);
    19. void QueuePop(Queue* pq);
    20. QDataType QueueFront(Queue* pq);
    21. QDataType QueueBack(Queue* pq);
    22. int Size(Queue* pq);
    23. int QueueEmpty(Queue* pq);
    24. void Print(Queue* pq);

    Queue.c

    1. #include "Queue.h"
    2. void QueueInit(Queue* pq)
    3. {
    4. assert(pq);
    5. pq->head = pq->tail = NULL;
    6. }
    7. void QueueDestroy(Queue* pq)
    8. {
    9. assert(pq);
    10. QueueNode* cur = pq->head;
    11. while (cur)
    12. {
    13. QueueNode* del = cur;
    14. cur = cur->next;
    15. free(del);
    16. }
    17. pq->head = pq->tail = NULL;
    18. }
    19. void QueuePush(Queue* pq, QDataType x)
    20. {
    21. assert(pq);
    22. QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    23. if (newNode == NULL)
    24. {
    25. perror("QueuePush error");
    26. exit(-1);
    27. }
    28. newNode->data = x;
    29. newNode->next = NULL;
    30. if (pq->tail == NULL)
    31. {
    32. pq->head = pq->tail = newNode;
    33. }
    34. else
    35. {
    36. pq->tail->next = newNode;
    37. pq->tail = newNode;
    38. }
    39. }
    40. void QueuePop(Queue* pq)
    41. {
    42. assert(pq);
    43. assert(!QueueEmpty(pq));
    44. if (pq->head->next == NULL)
    45. {
    46. free(pq->head);
    47. pq->head = pq->tail = NULL;
    48. }
    49. else
    50. {
    51. QueueNode* del = pq->head;
    52. pq->head = del->next;;
    53. free(del);
    54. }
    55. }
    56. QDataType QueueFront(Queue* pq)
    57. {
    58. assert(pq);
    59. assert(!QueueEmpty(pq));
    60. return pq->head->data;
    61. }
    62. QDataType QueueBack(Queue* pq)
    63. {
    64. assert(pq);
    65. return pq->tail->data;
    66. }
    67. int Size(Queue* pq)
    68. {
    69. assert(pq);
    70. int n = 0;
    71. QueueNode* cur = pq->head;
    72. while (cur)
    73. {
    74. n++;
    75. cur = cur->next;
    76. }
    77. return n;
    78. }
    79. int QueueEmpty(Queue* pq)
    80. {
    81. assert(pq);
    82. return (pq->head == pq->tail) && (pq->head == NULL) && (pq->tail == NULL);
    83. }
    84. void Print(Queue* pq)
    85. {
    86. QueueNode* cur = pq->head;
    87. while (cur)
    88. {
    89. printf("%d ", cur->data);
    90. cur = cur->next;
    91. }
    92. printf("\n");
    93. }

            实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型 时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。

    3. 栈和队列面试题

    20. 有效的括号

            先找左括号,找到左括号入栈。如果有左括号,再找到右括号就将左括号出栈。如果是右括号的一种,栈顶的是左括号的另外一种,那么就有问题。

    1. class Solution {
    2. public:
    3. bool isValid(string s) {
    4. stack<char> st;
    5. for(auto ch : s)
    6. {
    7. if(ch == '{' || ch == '[' || ch == '(')
    8. {
    9. st.push(ch);
    10. }
    11. else
    12. {
    13. if(st.empty())
    14. {
    15. return false;
    16. }
    17. if((ch == '}' && st.top() == '{')
    18. || (ch == ']' && st.top() == '[')
    19. || (ch == ')' && st.top() == '('))
    20. {
    21. st.pop();
    22. }
    23. else
    24. {
    25. return false;
    26. }
    27. }
    28. }
    29. return st.empty();
    30. }
    31. };

    225. 用队列实现栈

     

            以此类推,当pop的时候将除了最后一个数据从队列里出队列,进入另一个队列中,然后出队列,这就用队列实现了栈的功能。

            具体代码实现如下:

    1. class MyStack {
    2. public:
    3. MyStack() {
    4. }
    5. void push(int x) {
    6. if(q1.empty())
    7. q2.push(x);
    8. else
    9. q1.push(x);
    10. }
    11. int pop() {
    12. // 让q1是空,q2不是空
    13. if(q2.empty())
    14. {
    15. queue<int> tmp = q1;
    16. q1 = q2;
    17. q2 = tmp;
    18. }
    19. while(q2.size() > 1)
    20. {
    21. q1.push(q2.front());
    22. q2.pop();
    23. }
    24. int del = q2.front();
    25. q2.pop();
    26. return del;
    27. }
    28. int top() {
    29. if(q1.empty())
    30. return q2.back();
    31. else
    32. return q1.back();
    33. }
    34. bool empty() {
    35. return q1.empty() && q2.empty();
    36. }
    37. private:
    38. queue<int> q1;
    39. queue<int> q2;
    40. };
    41. /**
    42. * Your MyStack object will be instantiated and called as such:
    43. * MyStack* obj = new MyStack();
    44. * obj->push(x);
    45. * int param_2 = obj->pop();
    46. * int param_3 = obj->top();
    47. * bool param_4 = obj->empty();
    48. */

    232. 用栈实现队列

            这里上面的是用来出队列的,下面的是用来入队列的,上面的出栈到最后一个,然后将最后一个pop掉,然后再从入队列的入到出队列的中,如此往复就用栈实现了队列。

            具体代码实现如下:

    1. class MyQueue {
    2. public:
    3. MyQueue() {
    4. }
    5. void push(int x) {
    6. s1.push(x);
    7. }
    8. int pop() {
    9. while(s1.size() > 1)
    10. {
    11. s2.push(s1.top());
    12. s1.pop();
    13. }
    14. int tmp = s1.top();
    15. s1.pop();
    16. while(s2.size())
    17. {
    18. s1.push(s2.top());
    19. s2.pop();
    20. }
    21. return tmp;
    22. }
    23. int peek() {
    24. while(s1.size())
    25. {
    26. s2.push(s1.top());
    27. s1.pop();
    28. }
    29. int tmp = s2.top();
    30. while(s2.size())
    31. {
    32. s1.push(s2.top());
    33. s2.pop();
    34. }
    35. return tmp;
    36. }
    37. bool empty() {
    38. return s1.empty() && s1.empty();
    39. }
    40. private:
    41. stack<int> s1;
    42. stack<int> s2;
    43. };
    44. /**
    45. * Your MyQueue object will be instantiated and called as such:
    46. * MyQueue* obj = new MyQueue();
    47. * obj->push(x);
    48. * int param_2 = obj->pop();
    49. * int param_3 = obj->peek();
    50. * bool param_4 = obj->empty();
    51. */

    622. 设计循环队列

            我这里设置的循环队列是通过数组来实现的,通过多开一个空间,来进行判断队列的空和满,也就是数组的头和尾是一个位置就是空,尾的下一个位置是头就是满,当然这里需要通过取模来完成,其中有一些细节需要完善,然后push的时候就是头到下一个位置,pop的时候就是尾巴向前走一个位置。

            具体的实现看下面的代码,当然这里的代码是我写的思路,当然也会有其它思路。

    1. class MyCircularQueue {
    2. public:
    3. MyCircularQueue(int k) {
    4. n = k;
    5. a = (int*)malloc(sizeof(int) * (k + 1));
    6. head = tail = 0;
    7. }
    8. bool enQueue(int value) {
    9. if(isFull())
    10. return false;
    11. a[tail] = value;
    12. tail++;
    13. if(tail >= n)
    14. tail %= (n+1);
    15. return true;
    16. }
    17. bool deQueue() {
    18. if(isEmpty())
    19. return false;
    20. head++;
    21. if(head >= n)
    22. head %= (n+1);
    23. return true;
    24. }
    25. int Front() {
    26. if(head == tail)
    27. return -1;
    28. return a[head];
    29. }
    30. int Rear() {
    31. if(head == tail)
    32. return -1;
    33. int T = tail - 1;
    34. if(T < 0)
    35. T = n;
    36. return a[T];
    37. }
    38. bool isEmpty() {
    39. return head == tail;
    40. }
    41. bool isFull() {
    42. return head == (tail+1)%(n+1);
    43. }
    44. private:
    45. int* a;
    46. int n;//个数
    47. int head;
    48. int tail;
    49. };
    50. /**
    51. * Your MyCircularQueue object will be instantiated and called as such:
    52. * MyCircularQueue* obj = new MyCircularQueue(k);
    53. * bool param_1 = obj->enQueue(value);
    54. * bool param_2 = obj->deQueue();
    55. * int param_3 = obj->Front();
    56. * int param_4 = obj->Rear();
    57. * bool param_5 = obj->isEmpty();
    58. * bool param_6 = obj->isFull();
    59. */

            如上就是 栈和队列 的所有知识,如果大家喜欢看此文章并且有收获,可以支持下 兔7 ,给 兔7 三连加关注,你的关注是对我最大的鼓励,也是我的创作动力~!

            再次感谢大家观看,感谢大家支持!

  • 相关阅读:
    Git统计提交代码量
    滴滴可观测平台 Metrics 指标实时计算如何实现了又准又省?
    给 Helm 提一个 PR,重温开源项目参与过程
    在CentOS7下安装Oracle11教程
    线性表的应用 —— 静态链表
    单核与多核CPU的区别与联系-结合ESP32浅谈
    七个用于云原生世界的Java框架
    NumPy 切片和索引
    百度首个江苏智算中心落地 携手盐城共建200P算力规模
    IDEA乱码问题解决
  • 原文地址:https://blog.csdn.net/weixin_69725192/article/details/126449709