当前位置:   article > 正文

数据结构之栈的超详细讲解

数据结构之栈的超详细讲解

目录

引言

一.栈的概念

二.栈的结构

三.栈的实现

栈结构的实现

栈操作函数的声明

栈中方法的实现

栈的初始化

栈的销毁

入栈

出栈

取栈顶元素

判断栈中是否为空

获取栈中数据个数

四.测试 

代码展示:

结构展示:

五.小结

六.完整代码

Stack.h

Stack.c

text.c


引言

这个专题是专门对栈进行详细的讲解,栈这个数据结构其实和之前的顺序表和单链表一样,同样是线性结构,但它的限制更大,如果想看之前单链表和顺序表数据结构的实现,或者是之后的数据结构我现在还没出的,都可以订阅我这个数据结构初阶的专栏--http://t.csdnimg.cn/sz4xS.好了,话不多说,点赞关注我们开始!

一.栈的概念

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

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

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

栈这个数据结构可以总结为四个字:后进先出

二.栈的结构

因为栈也是一种线性结构,所以并不复杂,如下图所示:

栈这种结构在我们生活中其实并不少见,比如我们打羽毛球用的羽毛球桶,装子弹的弹匣,都满足后进先出的一个特性. 

三.栈的实现

栈结构的实现

我们可以用三种方法实现栈这个结构:

方法一:

我们用双向链表构建栈,如下图所示:

这样做的好处是:双向链表能很轻松的寻找前面的节点

方法二:

我们用单链表构建栈,如下图所示:

我们用单链表构建栈时,我们入栈时需要头插,因为单链表找前面的节点是不好找的

方法三:

我们用动态数组构建栈:

这个方法就类似于基于动态数组构建顺序表

那么这三种方法选择哪一种呢?

首先因为单链表的原因,我们先把双向链表PASS掉

接下来就在单链表和动态数组中选择

其实两者相差不大,但由于动态数组具有元素高效率存储,所以这里选择动态数组实现栈

代码展示:

  1. //栈的结构
  2. typedef int STDataType;
  3. typedef struct Stack
  4. {
  5. STDataType* a;
  6. int top;
  7. int capacity;
  8. }ST;

 注意:这里的STDataType和之前的链表和顺序表一样,方便后面进行类型的替换

a时我们的动态数组

top是我们的栈顶指针

capacity是我们的空间容量

栈操作函数的声明

对于线性表来说,操作函数大同小异,所以栈的操作函数其实跟单链表和顺序表差不多

下面便是操作函数的声明:

  1. //函数的声明
  2. //初始化和销毁
  3. void STInit(ST* pst);
  4. void STDestory(ST* pst);
  5. //入栈和出栈
  6. void STPush(ST* pst, STDataType x);
  7. void STPop(ST* pst);
  8. //取栈顶元素
  9. STDataType STTop(ST* pst);
  10. //判空
  11. bool STEmpty(ST* pst);
  12. //获取数据个数
  13. int STSize(ST* pst);

栈中方法的实现

栈的初始化

注意:

栈这里的初始化分为两种方式:

1.top指向-1,top指向栈顶元素,如下图所示:

注意:这里的top不能指向为0,因为这样的话,当top指为0时,不知道是否含有数据

2.top指向0,top指向栈顶元素的下一位,如下图所示:

这里我用了第二种,因为这里的top即为元素个数,对于后面的操作会方便一点.

  1. //初始化和销毁
  2. void STInit(ST* pst)
  3. {
  4. assert(pst);
  5. pst->a = NULL;
  6. //top指向栈顶数据的下一个位置
  7. pst->top = 0;
  8. //top指向栈顶数据
  9. //pst->top = -1;
  10. pst->capacity = 0;
  11. }

栈的销毁

  1. void STDestory(ST* pst)
  2. {
  3. assert(pst);
  4. free(pst->a);
  5. pst->a = NULL;
  6. pst->top = pst->capacity = 0;
  7. }

注意最后要将top和capacity置为0

入栈

和顺序表的插入数据类似,首先进行断言处理,再看空间是否够用,不够用就进行两倍扩容.

注意:这里使用了三目操作符,因为我们初始化capacity为0,两倍扩容之后还是为0,所以当它为0时,直接初始化为4,或者其他值.

  1. void STPush(ST* pst, STDataType x)
  2. {
  3. assert(pst);
  4. //扩容
  5. if (pst->top == pst->capacity)
  6. {
  7. int newcapcacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
  8. STDataType* tmp = (STDataType*)realloc(pst->a, newcapcacity * sizeof(STDataType));
  9. if (tmp == NULL)
  10. {
  11. perror("realloc fail!");
  12. return;
  13. }
  14. pst->a = tmp;
  15. pst->capacity = newcapcacity;
  16. }
  17. pst->a[pst->top] = x;
  18. pst->top++;
  19. }

出栈

这个很简单,只需top--即可

  1. void STPop(ST* pst)
  2. {
  3. assert(pst);
  4. assert(pst->top > 0);
  5. pst->top--;
  6. }

取栈顶元素

注意:这里需要额外对top进行判空处理

  1. //取栈顶元素
  2. STDataType STTop(ST* pst)
  3. {
  4. assert(pst);
  5. assert(pst->top > 0);
  6. return pst->a[pst->top - 1];
  7. }

判断栈中是否为空

top即为我们栈中元素的个数

  1. //判空
  2. bool STEmpty(ST* pst)
  3. {
  4. assert(pst);
  5. return pst->top == 0;
  6. }

获取栈中数据个数

  1. //获取数据个数
  2. int STSize(ST* pst)
  3. {
  4. assert(pst);
  5. return pst->top;
  6. }

四.测试 

我们入栈一些元素,再将它们打印出来.

代码展示:

  1. #include "Stack.h"
  2. int main()
  3. {
  4. ST s;
  5. STInit(&s);
  6. STPush(&s, 1);
  7. STPush(&s, 2);
  8. STPush(&s, 3);
  9. STPush(&s, 4);
  10. //遍历栈中的元素
  11. while (!STEmpty(&s))
  12. {
  13. printf("%d ", STTop(&s));
  14. STPop(&s);
  15. }
  16. }

结构展示:

后进先出没有问题

五.小结

栈这个数据结构对比顺序表和单链表的实现真的简单了不少,但它的OJ题可不简单,后面我会更新关于栈的经典OJ练习,如果觉得这篇博客对你有帮助的话,一定要点赞关注哦!如果你有任何问题后可以打在评论区,大家一起学习,共同进步!

六.完整代码

Stack.h

  1. #pragma once
  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. //栈的结构
  7. typedef int STDataType;
  8. typedef struct Stack
  9. {
  10. STDataType* a;
  11. int top;
  12. int capacity;
  13. }ST;
  14. //函数的声明
  15. //初始化和销毁
  16. void STInit(ST* pst);
  17. void STDestory(ST* pst);
  18. //入栈和出栈
  19. void STPush(ST* pst, STDataType x);
  20. void STPop(ST* pst);
  21. //取栈顶元素
  22. STDataType STTop(ST* pst);
  23. //判空
  24. bool STEmpty(ST* pst);
  25. //获取数据个数
  26. int STSize(ST* pst);

Stack.c

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "Stack.h"
  3. //初始化和销毁
  4. void STInit(ST* pst)
  5. {
  6. assert(pst);
  7. pst->a = NULL;
  8. //top指向栈顶数据的下一个位置
  9. pst->top = 0;
  10. //top指向栈顶数据
  11. //pst->top = -1;
  12. pst->capacity = 0;
  13. }
  14. void STDestory(ST* pst)
  15. {
  16. assert(pst);
  17. free(pst->a);
  18. pst->a = NULL;
  19. pst->top = pst->capacity = 0;
  20. }
  21. //入栈和出栈
  22. void STPush(ST* pst, STDataType x)
  23. {
  24. assert(pst);
  25. //扩容
  26. if (pst->top == pst->capacity)
  27. {
  28. int newcapcacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
  29. STDataType* tmp = (STDataType*)realloc(pst->a, newcapcacity * sizeof(STDataType));
  30. if (tmp == NULL)
  31. {
  32. perror("realloc fail!");
  33. return;
  34. }
  35. pst->a = tmp;
  36. pst->capacity = newcapcacity;
  37. }
  38. pst->a[pst->top] = x;
  39. pst->top++;
  40. }
  41. void STPop(ST* pst)
  42. {
  43. assert(pst);
  44. assert(pst->top > 0);
  45. pst->top--;
  46. }
  47. //取栈顶元素
  48. STDataType STTop(ST* pst)
  49. {
  50. assert(pst);
  51. assert(pst->top > 0);
  52. return pst->a[pst->top - 1];
  53. }
  54. //判空
  55. bool STEmpty(ST* pst)
  56. {
  57. assert(pst);
  58. return pst->top == 0;
  59. }
  60. //获取数据个数
  61. int STSize(ST* pst)
  62. {
  63. assert(pst);
  64. return pst->top;
  65. }

text.c

  1. #include "Stack.h"
  2. int main()
  3. {
  4. ST s;
  5. STInit(&s);
  6. STPush(&s, 1);
  7. STPush(&s, 2);
  8. STPush(&s, 3);
  9. STPush(&s, 4);
  10. //遍历栈中的元素
  11. while (!STEmpty(&s))
  12. {
  13. printf("%d ", STTop(&s));
  14. STPop(&s);
  15. }
  16. }

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

闽ICP备14008679号