【数据结构与算法】栈的实现(附源码)

简介: 【数据结构与算法】栈的实现(附源码)

一.栈的概念和结构

1.一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作

2.进行数据插入和删除操作的一端称为栈顶,另一端称为栈底

3.栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则;

压栈:向栈中插入数据;

出栈:从栈中取出数据;

图示:

 

其实用链表和数组都可以实现栈,但栈底就相当于链表的头,数组的第一个元素,栈顶就相当与链表的尾,数组的最后一个元素,当我们进行压栈或是出栈操作时,链表就需要找到尾,所以时间复杂度为O(N),而数组则是O(1),所以这里选择用数组实现栈比较好

用数组实现的话,就和前面的顺序表类似了。

顺序表

二.接口实现

A.初始化  Stackinit   销毁  Stackdestroy

1.Stackinit

1.这里数组的初始化就和顺序表那里是一样的了,需要用到动态内存管理的函数,如果不懂的话,建议去补一下这一块的知识哦;

2.这个top用来记录实时数据的数量,和顺序表那里的 sz 是一样的,但注意:

 <1>  如果初始化成0,那么这个 top 就指的是栈顶的下一个位置;

 <2>  如果初始化成-1,那么这个 top 就指的是栈顶的位置;

3.初始化容量,这由你自己决定。

1. void Stackinit(Stack* ps)
2. {
3.  assert(ps);
4. 
5.  ps->arr = (STdatatype*)malloc(sizeof(STdatatype) * MR_CAP);
6.  if (ps->arr == NULL)
7.  {
8.    perror("malloc fail");
9.    exit(-1);
10.   }
11.   ps->top = 0;   //表示的是栈顶的下一个位置
12.   ps->capacity = MR_CAP;   //默认容量
13. }

2.Stackdestroy

这个非常简单,直接看代码吧。

1. void Stackdestroy(Stack* ps)
2. {
3.  assert(ps);
4. 
5.  free(ps->arr);
6.  ps->arr = NULL;
7.  ps->top = 0;
8.  ps->capacity = 0;
9. }

B.插入 Stackpush  删除  Stackpop

1.Stackpush

在插入前,我们需要判断容量是否已满,若已满,则需要扩容。

1. void Stackpush(Stack* ps, STdatatype x)
2. {
3.  assert(ps);
4.  if (ps->top == ps->capacity)   //判断是否已满
5.  {
6.    STdatatype* tmp = (STdatatype*)realloc(ps->arr, 2 * sizeof(STdatatype) * ps->capacity);
7.    if (tmp == NULL)
8.    {
9.      perror("realloc fail");
10.       exit(-1);
11.     }
12.     ps->arr = tmp;
13.     ps->capacity *= 2;
14.   }
15.   ps->arr[ps->top] = x;
16.   ps->top++;   //数据入栈后,实时数据数量加1
17. }

2.Stackpop

删除前要注意栈是否为空,若为空则不能进行删除操作;

删除就是使 top 减1。

1. void Stackpop(Stack* ps)
2. {
3.  assert(ps);
4.  assert(ps->top);   //判断栈是否为空
5. 
6.  ps->top--;  //删除数据
7. }

C.出栈 Stacktop

出栈前需要判断栈是否为空,为空则无数据可出栈;

因为前面初始化的 top 是0,所以栈顶数据的下标是 top-1 ,如果初始化的 top 是-1,那么栈顶数据的下标则是 top 。

1. STdatatype Stacktop(Stack* ps)
2. {
3.  assert(ps);
4.  assert(ps->top);  //判断栈是否为空
5.  return ps->arr[ps->top - 1];  //栈顶数据的下标是 top-1
6. }

D. 栈的有效元素  Stacksize  判空 Stackempty

1.Stacksize

1.若初始化的 top 是0,则 top 就是栈的有效元素个数;

2.若初始化的 top 是-1,则 top+1 为栈的有效元素个数。

1. int Stacksize(Stack* ps)
2. {
3.  assert(ps);
4. 
5.  return ps->top;
6. }

2.Stackempty

1.如果 top 是0,则为空,返回 true;

2.如果 top 不是0,则不为空,返回 false 。

1. bool Stackempty(Stack* ps)
2. {
3.  assert(ps);
4. 
5.  return ps->top == 0;  //如果 top ==0 ,则这句代码为真,返回 true;反之,返回 false
6. }

三.源码

Stack.h

1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <assert.h>
4. #include <stdbool.h>
5. 
6. #define MR_CAP 5
7. 
8. typedef int STdatatype;
9. 
10. typedef struct Stack
11. {
12.   STdatatype* arr;
13.   int top;
14.   int capacity;
15. }Stack;
16. 
17. void Stackinit(Stack* ps);
18. 
19. void Stackpush(Stack* ps,STdatatype x);
20. 
21. void Stackpop(Stack* ps);
22. 
23. STdatatype Stacktop(Stack* ps);
24. 
25. int Stacksize(Stack* ps);
26. 
27. bool Stackempty(Stack* ps);
28. 
29. void Stackdestroy(Stack* ps);

Stack.c

1. #include "Stack.h"
2. 
3. void Stackinit(Stack* ps)
4. {
5.  assert(ps);
6. 
7.  ps->arr = (STdatatype*)malloc(sizeof(STdatatype) * MR_CAP);
8.  if (ps->arr == NULL)
9.  {
10.     perror("malloc fail");
11.     exit(-1);
12.   }
13.   ps->top = 0;
14.   ps->capacity = MR_CAP;
15. }
16. 
17. void Stackpush(Stack* ps, STdatatype x)
18. {
19.   assert(ps);
20.   if (ps->top == ps->capacity)
21.   {
22.     STdatatype* tmp = (STdatatype*)realloc(ps->arr, 2 * sizeof(STdatatype) * ps->capacity);
23.     if (tmp == NULL)
24.     {
25.       perror("realloc fail");
26.       exit(-1);
27.     }
28.     ps->arr = tmp;
29.     ps->capacity *= 2;
30.   }
31.   ps->arr[ps->top] = x;
32.   ps->top++;
33. }
34. 
35. void Stackpop(Stack* ps)
36. {
37.   assert(ps);
38.   assert(ps->top);
39. 
40.   ps->top--;
41. }
42. 
43. STdatatype Stacktop(Stack* ps)
44. {
45.   assert(ps);
46.   assert(ps->top);
47.   return ps->arr[ps->top - 1];
48. }
49. 
50. int Stacksize(Stack* ps)
51. {
52.   assert(ps);
53. 
54.   return ps->top;
55. }
56. 
57. bool Stackempty(Stack* ps)
58. {
59.   assert(ps);
60. 
61.   return ps->top == 0;
62. }
63. 
64. void Stackdestroy(Stack* ps)
65. {
66.   assert(ps);
67. 
68.   free(ps->arr);
69.   ps->arr = NULL;
70.   ps->top = 0;
71.   ps->capacity = 0;
72. }

test.c

1. #include "Stack.h"
2. 
3. void testStack()
4. {
5.  Stack st;
6. 
7.  Stackinit(&st);
8. 
9.  int i = 0;
10.   for (i = 1; i <= 8; i++)
11.   {
12.     Stackpush(&st, i);
13.   }
14.   printf("%d\n ", Stacksize(&st));
15.   /*while (!Stackempty(&st))
16.   {
17.     printf("%d  ", Stacktop(&st));
18.     Stackpop(&st);
19.   }*/
20.   printf("\n");
21.   Stackdestroy(&st);
22. }
23. 
24. int main()
25. {
26.   testStack();
27. 
28.   return 0;
29. 
30. }

🐲👻关于栈的讲解就到这里了,若有错误或是建议欢迎小伙伴们指出。🐯🤖

🥰🤩希望小伙伴们可以多多支持博主哦。😍😃

😁😄谢谢你的阅读。😼😸


目录
相关文章
|
2月前
|
算法 数据可视化 数据挖掘
基于EM期望最大化算法的GMM参数估计与三维数据分类系统python源码
本内容展示了基于EM算法的高斯混合模型(GMM)聚类实现,包含完整Python代码、运行效果图及理论解析。程序使用三维数据进行演示,涵盖误差计算、模型参数更新、结果可视化等关键步骤,并附有详细注释与操作视频,适合学习EM算法与GMM模型的原理及应用。
|
3月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
192 3
|
3月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
47 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
8月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
332 77
|
6月前
|
存储 自然语言处理 数据库
【数据结构进阶】AVL树深度剖析 + 实现(附源码)
在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
492 19
|
6月前
|
数据库 C++
【数据结构进阶】红黑树超详解 + 实现(附源码)
本文深入探讨了红黑树的实现原理与特性。红黑树是一种自平衡二叉搜索树,通过节点着色(红/黑)和特定规则,确保树的高度接近平衡,从而实现高效的插入、删除和查找操作。相比AVL树,红黑树允许一定程度的不平衡,减少了旋转调整次数,提升了动态操作性能。文章详细解析了红黑树的性质、插入时的平衡调整(变色与旋转)、查找逻辑以及合法性检查,并提供了完整的C++代码实现。红黑树在操作系统和数据库中广泛应用,其设计兼顾效率与复杂性的平衡。
1030 3
|
6月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
7月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
157 11
|
7月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。

热门文章

最新文章