• 数据结构·栈与队列介绍与实现


    目录

    栈的概念及结构

    概念选择题 

    栈的实现

    Stack.h

    Stack.c

    Test.c

    一道关于栈的oj题目

     20. 有效的括号

    描述

    解答代码

    队列的概念及结构

    队列的实现 

    Queue.h

    Queue.c

    Test.c

    结束语


    栈的概念及结构

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

     

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

    概念选择题 

    答案 -- 选中查看

    1、B

    2、C

    栈的实现

    Stack.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. //静态不考虑
    7. //#define N 100
    8. //typedef int STDataType;
    9. //struct Stack
    10. //{
    11. // STDataType a[N];
    12. // int top;
    13. //};
    14. typedef int STDataType;
    15. typedef struct Stack
    16. {
    17. STDataType* a;
    18. int top; //数据
    19. int capacity; //空间容量
    20. }ST;
    21. //初始化
    22. void StackInit(ST* ps);
    23. //销毁
    24. void StackDestroy(ST* ps);
    25. //入栈
    26. void StackPush(ST* ps , STDataType x); //根据栈的概念 栈只有一个地方可以插入
    27. //出栈
    28. void StackPop(ST* ps);
    29. //访问Top位置
    30. STDataType StackTop(ST* ps);
    31. //检查是否为空
    32. bool StackEmpty(ST* ps);
    33. //查看数据数量
    34. int StackSize(ST* ps); //调用函数来实现 -- 数据结构建议不要直接访问结构数据,一定要通过函数接口访问
    35. //解耦 -- 高内聚,低耦合

    Stack.c

    1. #include "Stack.h"
    2. //初始化
    3. void StackInit(ST* ps)
    4. {
    5. assert(ps);
    6. ps->a = NULL;
    7. ps->capacity = ps->top = 0;
    8. }
    9. //销毁
    10. void StackDestroy(ST* ps)
    11. {
    12. assert(ps);
    13. free(ps->a);
    14. ps->a = NULL;
    15. ps->capacity = ps->top = 0;
    16. }
    17. //入栈
    18. void StackPush(ST* ps, STDataType x)
    19. {
    20. assert(ps);
    21. //扩容
    22. if (ps->top == ps->capacity) //根据初始化的内容来判断
    23. {
    24. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    25. STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
    26. if (tmp == NULL)
    27. {
    28. perror("realloc fail");
    29. exit(-1);
    30. }
    31. ps->a = tmp;
    32. ps->capacity = newCapacity;
    33. }
    34. ps->a[ps->top] = x;
    35. ps->top++;
    36. }
    37. //出栈
    38. void StackPop(ST* ps)
    39. {
    40. assert(ps);
    41. assert(!StackEmpty(ps));
    42. --ps->top;
    43. }
    44. //访问Top位置
    45. STDataType StackTop(ST* ps)
    46. {
    47. assert(ps);
    48. assert(!StackEmpty(ps));
    49. return ps->a[ps->top - 1];
    50. }
    51. //检查是否为空
    52. bool StackEmpty(ST* ps)
    53. {
    54. assert(ps);
    55. return ps->top == 0;
    56. }
    57. //查看数据数量
    58. int StackSize(ST* ps)
    59. {
    60. assert(ps);
    61. return ps->top; //这里的top刚好是数据的下一个位置,自然就是数据个数
    62. }

    Test.c

    1. #include "Stack.h"
    2. void TestStack()
    3. {
    4. ST st;
    5. StackInit(&st);
    6. StackPush(&st, 1);
    7. StackPush(&st, 2);
    8. StackPush(&st, 3);
    9. printf("%d ", StackTop(&st));
    10. StackPop(&st);
    11. printf("%d ", StackTop(&st));
    12. StackPop(&st);
    13. StackPush(&st, 4);
    14. StackPush(&st, 5);
    15. while (!StackEmpty(&st))
    16. {
    17. printf("%d ", StackTop(&st)); //访问栈顶数据
    18. StackPop(&st); //根据栈的性质,访问一个弹出一个
    19. }
    20. printf("\n");
    21. }
    22. int main()
    23. {
    24. TestStack();
    25. return 0;
    26. }

    一道关于栈的oj题目

     20. 有效的括号

    给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

    有效字符串需满足:

    左括号必须用相同类型的右括号闭合。
    左括号必须以正确的顺序闭合。

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/valid-parentheses

    示例 1:

    输入:s = "( )"
    输出:true
    示例 2:

    输入:s = "( )[ ]{ }"
    输出:true
    示例 3:

    输入:s = "( ]"
    输出:false
    示例 4:

    输入:s = "( [ ) ]"
    输出:false
    示例 5:

    输入:s = "{ [ ] }"
    输出:true

    提示:

    • 1 <= s.length <= 104
    • s 仅由括号 '()[]{}' 组成

    描述

    C没有栈的,要用C解决只可以自己写个栈解决

    解答代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. typedef int STDataType;
    6. typedef struct Stack
    7. {
    8. STDataType* a;
    9. int top; //数据
    10. int capacity; //空间容量
    11. }ST;
    12. //初始化
    13. void StackInit(ST* ps);
    14. //销毁
    15. void StackDestroy(ST* ps);
    16. //入栈
    17. void StackPush(ST* ps , STDataType x); //根据栈的概念 栈只有一个地方可以插入
    18. //出栈
    19. void StackPop(ST* ps);
    20. //访问Top位置
    21. STDataType StackTop(ST* ps);
    22. //检查是否为空
    23. bool StackEmpty(ST* ps);
    24. //查看数据数量
    25. int StackSize(ST* ps); //调用函数来实现 -- 数据结构建议不要直接访问结构数据,一定要通过函数接口访问
    26. //解耦 -- 高内聚,低耦合
    27. //初始化
    28. void StackInit(ST* ps)
    29. {
    30. assert(ps);
    31. ps->a = NULL;
    32. ps->capacity = ps->top = 0;
    33. }
    34. //销毁
    35. void StackDestroy(ST* ps)
    36. {
    37. assert(ps);
    38. free(ps->a);
    39. ps->a = NULL;
    40. ps->capacity = ps->top = 0;
    41. }
    42. //入栈
    43. void StackPush(ST* ps, STDataType x)
    44. {
    45. assert(ps);
    46. //扩容
    47. if (ps->top == ps->capacity) //根据初始化的内容来判断
    48. {
    49. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    50. STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
    51. if (tmp == NULL)
    52. {
    53. perror("realloc fail");
    54. exit(-1);
    55. }
    56. ps->a = tmp;
    57. ps->capacity = newCapacity;
    58. }
    59. ps->a[ps->top] = x;
    60. ps->top++;
    61. }
    62. //出栈
    63. void StackPop(ST* ps)
    64. {
    65. assert(ps);
    66. assert(!StackEmpty(ps));
    67. --ps->top;
    68. }
    69. //访问Top位置
    70. STDataType StackTop(ST* ps)
    71. {
    72. assert(ps);
    73. assert(!StackEmpty(ps));
    74. return ps->a[ps->top - 1];
    75. }
    76. //检查是否为空
    77. bool StackEmpty(ST* ps)
    78. {
    79. assert(ps);
    80. return ps->top == 0;
    81. }
    82. //查看数据数量
    83. int StackSize(ST* ps)
    84. {
    85. assert(ps);
    86. return ps->top; //这里的top刚好是数据的下一个位置,自然就是数据个数
    87. }
    88. bool isValid(char * s){
    89. ST st;
    90. StackInit(&st);
    91. while(*s)
    92. {
    93. if(*s == '{' || *s == '[' || *s == '(')
    94. {
    95. StackPush(&st, *s);
    96. }
    97. else
    98. {
    99. if(StackEmpty(&st)) //如果栈为空就说明一定不匹配 -- 数量不匹配
    100. {
    101. StackDestroy(&st); //销毁空间
    102. return false;
    103. }
    104. char top = StackTop(&st);//保存Top 数据 再弹出来
    105. StackPop(&st); //记得弹出来Top
    106. if((*s == '}' && top != '{')
    107. || (*s == ']' && top != '[')
    108. || (*s == ')' && top != '('))
    109. {
    110. StackDestroy(&st); //销毁空间
    111. return false;
    112. }
    113. }
    114. ++s;
    115. }
    116. //栈不为空 -- 但是数量还是不匹配,只有左括号 -- 这也是不匹配
    117. bool flag = StackEmpty(&st);
    118. StackDestroy(&st); //销毁空间
    119. return flag;
    120. }

    把上面写的栈搬了过来

    队列的概念及结构

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

     

    队列一般体现公平性 -- 比如在银行中的排队,先排队先办理,即先进先出,出于这点,使用链表更适合实现

    队列的实现 

    Queue.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. //能用单链表解决问题就可以用单链表 -- 没必要使用双向循环链表,这属于有点小题大做了
    7. typedef int QDataType;
    8. typedef struct QueueNode
    9. {
    10. struct QueueNode* next;
    11. QDataType data;
    12. }QNode;
    13. //再定义一个节点来存放两个指针,方便后面操作
    14. typedef struct Queue
    15. {
    16. //尾指针
    17. QNode* tail;
    18. //头指针
    19. QNode* head;
    20. int size;
    21. }Queue;
    22. //初始化 -- 到现在有三种不用二级指针来初始化结构体了 返回值、哨兵位的头节点和这里的创立一个新的结构体放俩这种
    23. void QueueInit(Queue* pq);
    24. //销毁
    25. void QueueDestroy(Queue* pq);
    26. //入队列 -- 根据队列的性质 只尾插
    27. void QueuePush(Queue* pq,QDataType x);
    28. //出队列 -- 根据队列的性质 只头删
    29. void QueuePop(Queue* pq);
    30. //查看头
    31. QDataType QueueFront(Queue* pq);
    32. //查看尾
    33. QDataType QueueBack(Queue* pq);
    34. //判断是否为空
    35. bool QueueEmpty(Queue* pq);
    36. //查看节点长度
    37. int QueueSize(Queue* pq);

    Queue.c

    1. #include "Queue.h"
    2. //初始化 -- 到现在有三种不用二级指针来初始化结构体了 返回值、头节点
    3. void QueueInit(Queue* pq)
    4. {
    5. assert(pq); //因为这里是自己创立的节点是不可能为空的,为空就是出问题了
    6. pq->head = pq->tail = NULL;
    7. pq->size = 0;
    8. }
    9. //销毁
    10. void QueueDestroy(Queue* pq)
    11. {
    12. assert(pq);
    13. QNode* cur = pq->head;
    14. while (cur)
    15. {
    16. QNode* del = cur;
    17. cur = cur->next;
    18. free(del);
    19. }
    20. pq->head = pq->tail = NULL; //要改变什么就需要什么的指针,这里置空就可以了
    21. }
    22. //入队列 -- 根据队列的性质 只尾插
    23. void QueuePush(Queue* pq, QDataType x)
    24. {
    25. assert(pq);
    26. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    27. if (newnode == NULL)
    28. {
    29. perror("malloc fail");
    30. exit(-1);
    31. }
    32. else
    33. {
    34. newnode->data = x;
    35. newnode->next = NULL; //这里置空,下面就不需要置空了
    36. }
    37. if (pq->tail == NULL)
    38. {
    39. pq->head = pq->tail = newnode;
    40. }
    41. else
    42. {
    43. pq->tail->next = newnode;
    44. pq->tail = newnode;
    45. }
    46. pq->size++;
    47. }
    48. //出队列 -- 根据队列的性质 只头删
    49. void QueuePop(Queue* pq)
    50. {
    51. assert(pq);
    52. assert(!QueueEmpty(pq));
    53. if (pq->head->next == NULL) //防止只剩下一个节点时候再删,就会导致野指针
    54. {
    55. free(pq->head);
    56. pq->tail = pq->head = NULL;
    57. }
    58. else
    59. {
    60. QNode* del = pq->head;
    61. pq->head = pq->head->next;
    62. free(del);
    63. del = NULL;
    64. }
    65. pq->size--;
    66. }
    67. //查看头
    68. QDataType QueueFront(Queue* pq)
    69. {
    70. assert(pq);
    71. assert(!QueueEmpty(pq));
    72. return pq->head->data;
    73. }
    74. //查看尾
    75. QDataType QueueBack(Queue* pq)
    76. {
    77. assert(pq);
    78. assert(!QueueEmpty(pq));
    79. return pq->tail->data;
    80. }
    81. //判断是否为空
    82. bool QueueEmpty(Queue* pq)
    83. {
    84. assert(pq);
    85. return pq->head == NULL && pq->tail == NULL; //理论上两个都应该为空才为空,一般一个为空就都会为空,不是就出问题了
    86. }
    87. //查看节点长度
    88. int QueueSize(Queue* pq)
    89. {
    90. assert(pq);
    91. //这样写就变为O(N)级别了 为此需要稍作修改
    92. //QNode* cur = pq->head;
    93. //int n = 0;
    94. //while (cur)
    95. //{
    96. // ++n;
    97. // cur = cur->next;
    98. //}
    99. //return n;
    100. return pq->size;
    101. }

    Test.c

    1. #include "Queue.h"
    2. void TestQueue()
    3. {
    4. Queue q; //这里创立了一个节点,使用不会为空
    5. //初始化
    6. QueueInit(&q);
    7. QueuePush(&q, 1);
    8. QueuePush(&q, 2);
    9. printf("%d ", QueueFront(&q));
    10. QueuePop(&q);
    11. //打印尾部
    12. printf("%d ", QueueFront(&q));
    13. QueuePush(&q, 3);
    14. QueuePush(&q, 4);
    15. while (!QueueEmpty(&q))
    16. {
    17. printf("%d ", QueueFront(&q));
    18. QueuePop(&q);
    19. }
    20. printf("\nsize =%d \n",QueueSize(&q));
    21. QueueDestroy(&q);
    22. }
    23. int main()
    24. {
    25. TestQueue();
    26. return 0;
    27. }

    结束语

    枝上柳绵吹又少,天涯何处无芳草。
                                                            宋·苏轼 《蝶恋花·春景》 

  • 相关阅读:
    Prometheus、node_exporter、Grafana端口修改(端口占用)
    多态(polymorphic)
    PySpark的运行出错:Py4JJavaError
    提升,方法比努力重要!不懂这几点再多的努力也白费!
    茶饮门店本地生活抖音团购运营方案计划书
    ubuntu下网卡插入网线后仍然不连接
    安卓 view淡入淡出(fade in fade out) kotlin
    CiscoCUCM电话注册
    MySQL索引分类及相关概念辨析
    PyTorch模型定义和相关使用
  • 原文地址:https://blog.csdn.net/weixin_67595436/article/details/126242893