• 栈和队列(8.4)


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

    后入栈的数据先出来,例如存入1,2,3,出栈的顺序是3,2,1。

    1.2 栈的实现

    思考一下,栈的实现是用数组还是链表更合适呢?

    都可以实现,但相对来说,数组更好一些,数组的尾插尾删效率更高。

    typedef int STDataType;
    //支持动态增长的栈
    typedef struct Stack
    {
        STDataType* a;
        int top;//栈顶
        int capacity;//容量
    }ST;

    1.2.1 栈初始化

    存在一个问题,栈顶 top 应该初始化为多少?

    如果初始化为 0,入栈一个数据 top ++,意味着 top 是栈顶元素的下一个位置

    初始化为 -1, top 则为栈顶元素本身

    这两种做法都是可以的。

    完整代码:
    头文件:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. //定义栈
    7. 静态栈(一般不用)
    8. //#define N 10
    9. //struct Stack
    10. //{
    11. // int a[N];
    12. // int top;
    13. //};
    14. typedef int STDataType;
    15. //支持动态增长的栈
    16. typedef struct Stack
    17. {
    18. STDataType* a;
    19. int top;//栈顶
    20. int capacity;//容量
    21. }ST;
    22. // 初始化栈
    23. void STInit(ST* ps);
    24. // 入栈
    25. void STPush(ST* ps, STDataType x);
    26. // 出栈
    27. void STPop(ST* ps);
    28. // 获取栈顶元素
    29. STDataType STTop(ST* ps);
    30. // 获取栈中有效元素个数
    31. int STSize(ST* ps);
    32. // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
    33. bool STEmpty(ST* ps);
    34. // 销毁栈
    35. void STDestroy(ST* ps);

    测试文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"Stack.h"
    3. void TestStack1()
    4. {
    5. //初始化结构体
    6. ST st;
    7. STInit(&st);
    8. STPush(&st, 1);
    9. STPush(&st, 2);
    10. STPush(&st, 3);
    11. STPush(&st, 4);
    12. //链表不为空
    13. while (!STEmpty(&st))
    14. {
    15. //打印栈顶
    16. printf("%d ",STTop(&st));
    17. //打印一个,出栈一个
    18. STPop(&st);
    19. }
    20. printf("\n");
    21. STDestroy(&st);
    22. }
    23. int main()
    24. {
    25. TestStack1();
    26. return 0;
    27. }

    实现文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"Stack.h"
    3. // 初始化栈
    4. void STInit(ST* ps)
    5. {
    6. assert(ps);
    7. ps->a = NULL;
    8. ps->capacity = 0;
    9. ps->top = 0;
    10. }
    11. // 销毁栈
    12. void STDestroy(ST* ps)
    13. {
    14. assert(ps);
    15. //释放
    16. free(ps->a);
    17. ps->a = NULL;
    18. ps->top = ps->capacity = 0;
    19. }
    20. // 入栈
    21. void STPush(ST* ps, STDataType x)
    22. {
    23. assert(ps);
    24. //如果放满,扩容
    25. if (ps->top == ps->capacity)
    26. {
    27. //如果容量为空,就先赋值,如果不为空,就将容量翻倍
    28. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    29. //直接用realloc申请空间,当原本没有空间时,它等同于malloc
    30. //先用tmp承接开辟的空间,以免开辟失败破坏原空间
    31. STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * newCapacity);
    32. if (tmp == NULL)
    33. {
    34. perror("realloc");
    35. exit(-1);
    36. }
    37. ps->a = tmp;
    38. ps->capacity = newCapacity;
    39. }
    40. //放值
    41. ps->a[ps->top] = x;
    42. ps->top++;
    43. }
    44. // 出栈
    45. void STPop(ST* ps)
    46. {
    47. assert(ps);
    48. //top为0说明栈空,不能继续删
    49. assert(ps->top > 0);
    50. --ps->top;
    51. }
    52. // 获取栈中有效元素个数
    53. int STSize(ST* ps)
    54. {
    55. assert(ps);
    56. //top是栈顶元素的下一个位置,正好是size
    57. return ps->top;
    58. }
    59. // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
    60. bool STEmpty(ST* ps)
    61. {
    62. assert(ps);
    63. //top为0栈为空
    64. return ps->top == 0;
    65. }
    66. // 获取栈顶元素
    67. STDataType STTop(ST* ps)
    68. {
    69. assert(ps);
    70. //top为0说明栈空,没有元素
    71. assert(ps->top > 0);
    72. return ps->a[ps->top - 1];
    73. }

    例题:

    20. 有效的括号 - 力扣(LeetCode)

    思路:由于左括号需要以正确的顺序闭合,栈的特性完美适配这一要求:我们创建一个栈(栈的基本操作我们直接cv前面的代码),将左括号入栈,然后取栈顶,与栈外的右括号相匹配,如果刚好完全匹配没有剩余,则为有效,相反,左括号或右括号中任一有剩余则为无效。

    1. typedef char STDataType;
    2. //支持动态增长的栈
    3. typedef struct Stack
    4. {
    5. STDataType* a;
    6. int top;//栈顶
    7. int capacity;//容量
    8. }ST;
    9. // 初始化栈
    10. void STInit(ST* ps);
    11. // 入栈
    12. void STPush(ST* ps, STDataType x);
    13. // 出栈
    14. void STPop(ST* ps);
    15. // 获取栈顶元素
    16. STDataType STTop(ST* ps);
    17. // 获取栈中有效元素个数
    18. int STSize(ST* ps);
    19. // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
    20. bool STEmpty(ST* ps);
    21. // 销毁栈
    22. void STDestroy(ST* ps);
    23. // 初始化栈
    24. void STInit(ST* ps)
    25. {
    26. assert(ps);
    27. ps->a = NULL;
    28. ps->capacity = 0;
    29. ps->top = 0;
    30. }
    31. // 销毁栈
    32. void STDestroy(ST* ps)
    33. {
    34. assert(ps);
    35. //释放
    36. free(ps->a);
    37. ps->a = NULL;
    38. ps->top = ps->capacity = 0;
    39. }
    40. // 入栈
    41. void STPush(ST* ps, STDataType x)
    42. {
    43. assert(ps);
    44. //如果放满,扩容
    45. if (ps->top == ps->capacity)
    46. {
    47. //如果容量为空,就先赋值,如果不为空,就将容量翻倍
    48. int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    49. //直接用realloc申请空间,当原本没有空间时,它等同于malloc
    50. //先用tmp承接开辟的空间,以免开辟失败破坏原空间
    51. STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * newCapacity);
    52. if (tmp == NULL)
    53. {
    54. perror("realloc");
    55. exit(-1);
    56. }
    57. ps->a = tmp;
    58. ps->capacity = newCapacity;
    59. }
    60. //放值
    61. ps->a[ps->top] = x;
    62. ps->top++;
    63. }
    64. // 出栈
    65. void STPop(ST* ps)
    66. {
    67. assert(ps);
    68. //top为0说明栈空,不能继续删
    69. assert(ps->top > 0);
    70. --ps->top;
    71. }
    72. // 获取栈中有效元素个数
    73. int STSize(ST* ps)
    74. {
    75. assert(ps);
    76. //top是栈顶元素的下一个位置,正好是size
    77. return ps->top;
    78. }
    79. // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
    80. bool STEmpty(ST* ps)
    81. {
    82. assert(ps);
    83. //top为0栈为空
    84. return ps->top == 0;
    85. }
    86. // 获取栈顶元素
    87. STDataType STTop(ST* ps)
    88. {
    89. assert(ps);
    90. //top为0说明栈空,没有元素
    91. assert(ps->top > 0);
    92. return ps->a[ps->top - 1];
    93. }
    94. bool isValid(char * s){
    95. ST st;
    96. char top;
    97. STInit(&st);
    98. while(*s)
    99. {
    100. //如果为左括号
    101. if(*s=='{'||*s=='('||*s=='[')
    102. {
    103. //入栈
    104. STPush(&st, *s);
    105. }
    106. //如果为右括号
    107. else
    108. {
    109. //栈内为空,说明左右括号数量不匹配
    110. if(STEmpty(&st))
    111. {
    112. //销毁空间,返回
    113. STDestroy(&st);
    114. return false;
    115. }
    116. //栈内不为空,取栈顶与栈外的右边括号匹配
    117. top=STTop(&st);
    118. //取出之后就出栈,以便于后面的元素出栈
    119. STPop(&st);
    120. //左右不匹配
    121. if(*s=='}'&&top!='{'
    122. ||*s==']'&&top!='['
    123. ||*s==')'&&top!='(')
    124. {
    125. STDestroy(&st);
    126. return false;
    127. }
    128. }
    129. s++;
    130. }
    131. //通过遍历说明右括号完全被匹配,栈内的左括号可能有剩余,没有剩余ture,有剩余false
    132. bool ret=STEmpty(&st);
    133. return ret;
    134. STDestroy(&st);
    135. }
  • 相关阅读:
    vue 自动生成面包屑导航
    208道最常见的Java面试题整理(面试必备)
    Linux_文件系统(内存角度)
    vite vite.config.js中的配置
    QT设置mainwindow的窗口title
    学习提高:Elasticsearch7.X 多层嵌套查询SpringBoot项目,源码示例,不区分大小写配置+搜索实现
    自动驾驶感知算法实战13——自动驾驶感知未来发展方向分享
    HDLbits : Module addsub
    AB实验--科学增长
    推荐几款火爆的Python在线编辑器
  • 原文地址:https://blog.csdn.net/dn235z/article/details/133972842