• 第三章、栈和队列


     在大二懵懵懂懂上数据结构的时候,当时学完了栈、队列、树我都不知道学这些数据结构有什么用,直到我大四在力扣上刷到这道题20. 有效的括号 - 力扣(LeetCode),这道题的算法用栈是最简单的,从此我才知道这些数据结构原来这么有用,于是我赶紧回过头来重新刷一遍数据结构!

    我主要是用的这本教材

     并且由于我在自学C++,因此教材中用C实现的部分我全部换成C++进行实现(也不用改太多东西的一说..)

    栈的顺序存储结构

    栈是一种先进后出的结构。

    我们对顺序栈的实现是用一个数组(容纳栈中的元素)以及一个栈顶元素(指向栈顶)来实现!

     下面实现初始化栈、销毁栈、判断栈是否为空、进栈、出栈、取栈顶元素等操作:

    1. #include
    2. using namespace std;
    3. typedef int Elemtype; //栈内元素的类型
    4. #define MaxSize 50
    5. class SqStack
    6. {
    7. public:
    8. Elemtype data[MaxSize];
    9. int top;
    10. };
    11. void InitStack(SqStack *&s)
    12. {
    13. s = new SqStack;
    14. s->top = -1;
    15. }
    16. void DestroyStack(SqStack *&s)
    17. {
    18. delete s;
    19. }
    20. bool StackIsEmpty(SqStack *s)
    21. {
    22. return (s->top == -1);
    23. }
    24. bool Push(SqStack *&s, Elemtype e)
    25. {
    26. if (s->top == MaxSize - 1)
    27. return false;
    28. s->top++;
    29. s->data[s->top] = e; // !!!
    30. return true;
    31. }
    32. bool Pop(SqStack *&s, Elemtype &e) //只能出栈栈顶元素,e用来保存出栈的栈顶元素
    33. {
    34. if (s->top == -1)
    35. return false;
    36. e = s->data[s->top];
    37. s->top--;
    38. return true;
    39. }
    40. bool GetTop(SqStack *&s, Elemtype &e)
    41. {
    42. if (s->top == -1)
    43. return false;
    44. e = s->data[s->top];
    45. return true;
    46. }

     再次给出一个验证上面函数的主函数防止小白不会用这些函数。

    1. int main()
    2. {
    3. SqStack *s; //定义栈指针
    4. InitStack(s); //初始化栈
    5. Push(s, 1); //进栈
    6. Push(s, 2);
    7. int temp;
    8. GetTop(s, temp);//取得栈顶元素
    9. cout << "the top element of the stack:" << temp << endl;
    10. Pop(s, temp); // 出栈
    11. GetTop(s, temp);
    12. cout << "the top element of the stack:" << temp << endl;
    13. system("pause");
    14. return 0;
    15. }

    栈的链式存储结构

    刚刚的额顺序栈采用数组存取元素,所以我们当然也可以用链式存储结构进行存储!

    链栈的优点是不存在栈满上溢的情况,并且插入和删除结点都很方便,时间复杂度为O(1)。

     注意:这里头节点指向栈顶节点,因此我们进栈相当于头插法!

     在实现方面,我们的链栈的一个结点可以用一个指针(指向下一个元素)以及一个变量(存取自身元素的值)。

     同样的,实现初始化栈、销毁栈、判断栈是否为空、进栈、出栈、取栈顶元素等操作:

    1. #include
    2. using namespace std;
    3. typedef int ElemType;
    4. class LinkStNode
    5. {
    6. public:
    7. ElemType data;
    8. LinkStNode *next;
    9. };
    10. void InitStack(LinkStNode *&s)
    11. {
    12. s = new LinkStNode;
    13. s->next = NULL;
    14. }
    15. void DestroyStack(LinkStNode *&s)
    16. {
    17. LinkStNode *pre = s, *p = s->next;
    18. while (p != NULL)
    19. {
    20. delete p;
    21. pre = p;
    22. p = pre->next;
    23. }
    24. delete pre;
    25. }
    26. bool StackIsEmpty(LinkStNode *&s)
    27. {
    28. return (s->next == NULL);
    29. }
    30. void Push(LinkStNode *&s, ElemType e)
    31. {
    32. LinkStNode *p;
    33. p = new LinkStNode;
    34. p->data = e;
    35. p->next = s->next;
    36. s->next = p;
    37. }
    38. bool Pop(LinkStNode *&s, ElemType &e)
    39. {
    40. LinkStNode *p;
    41. if (s->next == NULL)
    42. return false;
    43. p = s->next;
    44. e = p->data;
    45. s->next = p->next;
    46. delete p;
    47. return true;
    48. }
    49. bool GetTop(LinkStNode *&s, ElemType &e)
    50. {
    51. if (s->next == NULL)
    52. return false;
    53. LinkStNode *p = s->next;
    54. e = p->data;
    55. return true;
    56. }

    顺序队列

    队列是一种先进先出的结构,仅限制在一端进行插入,一端进行删除。

    实现方面我们用一个数组(容纳队内元素)以及一个队头变量front和队尾变量rear表示。

     同样的,我们实现初始化、销毁等等操作:

    1. #include
    2. using namespace std;
    3. typedef int ElemType;
    4. #define MaxSize 50
    5. class SqQueue
    6. {
    7. public:
    8. ElemType data[MaxSize];
    9. ElemType front,rear;//队头和队尾指针
    10. };
    11. void InitQueue(SqQueue *&q)
    12. {
    13. q = new SqQueue;
    14. q->front = q->rear = -1;
    15. }
    16. void DestroyQueue(SqQueue *&q)
    17. {
    18. delete q;
    19. }
    20. bool QueueIsEmpty(SqQueue *&q)
    21. {
    22. return(q->front == q->rear);
    23. }
    24. //进队列
    25. bool enQueue(SqQueue *&q, ElemType e)
    26. {
    27. if(q->rear == MaxSize - 1)
    28. return false;//队列满
    29. q->rear++;
    30. q->data[q->rear] = e;
    31. return true;
    32. }
    33. //出队列
    34. bool deQueue(SqQueue *&q, ElemType &e)
    35. {
    36. if(q->front == q->rear)
    37. return false;//队列空
    38. q->front++;
    39. e = q->data[q->front]; //说是出队,但是出队元素还在数组中,环形队列也只是进行覆盖!
    40. return true;
    41. }

    环形队列

    我们发现上述的队列结构队列满可能不是真的队列满

     这种虽然队尾元素已经到最后了,但是实际上对头元素前面还有空余!

    于是我们提出了环形队列!

     

     也就是说我们牺牲了一个元素空间来换取队满条件!

    同样的,我们实现一些基本函数:

    1. #include
    2. using namespace std;
    3. typedef int ElemType;
    4. #define MaxSize 50
    5. class SqQueue
    6. {
    7. public:
    8. ElemType data[MaxSize];
    9. int front, rear; //队头和队尾指针
    10. };
    11. void InitQueue(SqQueue *&q)
    12. {
    13. q = new SqQueue;
    14. q->front = q->rear = 0;
    15. }
    16. void DestroyQueue(SqQueue *&q)
    17. {
    18. delete q;
    19. }
    20. bool QueueIsEmpty(SqQueue *&q)
    21. {
    22. return(q->front == q->rear);
    23. }
    24. bool enQueue(SqQueue *&q, ElemType e)
    25. {
    26. if((q->rear + 1) % MaxSize == q->front)
    27. return false;
    28. q->rear++;
    29. q->data[q->rear] = e;
    30. return true;
    31. }
    32. bool deQueue(SqQueue *&q, ElemType &e)
    33. {
    34. if(QueueIsEmpty(q))
    35. return false;
    36. q->front++;
    37. e = q->data[q->front];
    38. return true;
    39. }

    队列的链式存储结构

    由于队列的数据元素的逻辑关系呈线性,同样的,我们可以采用链表进行存储。

    也是采用一个指针(指向下个元素)以及一个data变量存储自身数据。但是由于我们的链队有两个指针,因此我们要定义两个类!一个链节点类,一个链队类!

    同样的,对一些函数进行实现: 

    1. #include
    2. using namespace std;
    3. typedef int ElemType;
    4. class DataNode //链队中数据节点
    5. {
    6. public:
    7. ElemType data;
    8. DataNode *next;
    9. };
    10. class LinkQuNode //链队中头节点
    11. {
    12. public:
    13. DataNode *front; //注意有两个节点哦
    14. DataNode *rear;
    15. };
    16. void InitQueue(LinkQuNode *&q)
    17. {
    18. LinkQuNode *q = new LinkQuNode;
    19. q->front = q->rear = NULL;
    20. }
    21. void DestroyQueue(LinkQuNode *&q) //对于前面的顺序队没有多余指针,我们可以直接销毁。而这里链队必须销毁后面跟着的一些指针,不然他们就变成孤魂野鬼了!
    22. {
    23. DataNode *pre = q->front, *p;
    24. if (pre->next != NULL)
    25. {
    26. p = pre->next;
    27. while (p != NULL)
    28. {
    29. delete pre;
    30. pre = p;
    31. p = p->next;
    32. }
    33. delete p;
    34. }
    35. delete q;
    36. }
    37. bool QueuqIsEmpty(LinkQuNode *q)
    38. {
    39. return (q->rear == NULL);
    40. }
    41. //进队
    42. bool enQueue(LinkQuNode *&q, ElemType e)
    43. {
    44. DataNode *p = new DataNode;
    45. p->data = e;
    46. p->next = NULL;
    47. if (QueuqIsEmpty(q))
    48. q->front = q->rear = p;
    49. else
    50. {
    51. q->rear->next = p;
    52. q->rear = p;
    53. }
    54. }
    55. bool deQueue(LinkQuNode *&q, ElemType &e)
    56. {
    57. DataNode *t = q->front;
    58. if (QueuqIsEmpty(q))
    59. return false;
    60. else if (q->front == q->rear) //只有一个元素时,从队头删除也会影响到队尾
    61. {
    62. q->front = q->rear = NULL;
    63. }
    64. else
    65. {
    66. e = q->rear->data;
    67. q->front = q->front->next;
    68. }
    69. delete t;
    70. return true;
    71. }

  • 相关阅读:
    使用 Docker 部署 VS Code in The Browser
    MacOS使用clion配置mounriver 工具链
    Java---数据库---JDBC
    y136.第七章 服务网格与治理-Istio从入门到精通 -- Istio部署模型(二二)
    python库安装中Microsoft Visual C++ is required解决方法
    C++基础——类与对象
    【leetcode】【初级算法】【链表5】回文链表
    2023年亚太杯数学建模思路 - 案例:异常检测
    19-渐变
    数字图像处理(入门篇)一 图像的数字化与表示
  • 原文地址:https://blog.csdn.net/qq_55621259/article/details/126356467