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

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

一.栈的概念和结构

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. }

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

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

😁😄谢谢你的阅读。😼😸


目录
相关文章
|
19天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
100 9
|
10天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
19 1
|
13天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
18天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
60 16
|
14天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
59 8
|
14天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
47 7
|
18天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
68 8
|
16天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
18天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
46 4
|
21天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
49 4