欢迎各位大佬交流!
目录
一、栈的概念及结构
1、栈的基本概念
栈(Stack)是一种遵循后进先出(LIFO, Last In First Out)原则的线性数据结构;
仅允许在表的一端(称为栈顶,Top)进行插入(入栈,Push)和删除(出栈,Pop)操作,另一端称为栈底(Bottom);
2、栈的结构
栈的存储结构既可以用数组来实现,也能用链表来实现;
注意:此处我们说的链表是单链表!不考虑双向链表是因为双向链表空间较大,且双向链表功能复杂,性能较低!
那么到底是用数组来实现栈?还是链表呢?
我们通过一些操作的时间复杂度进行分析:
a、对于入栈而言:如果是链表实现的栈,首先要找到栈顶元素,显然需要O(N)级别的时间复杂度;
而如果是数组实现的栈,我们可以直接使用 top 这个下标,申请完空间之后直接尾插即可;
b、对于出栈而言:如果是链表实现的栈,首先要找到倒数第二个节点,显然依旧是O(N)级别的时间复杂度;
而如果是数组实现的栈,直接 top-- 即可;
综上,我们选择用数组来实现栈;
二、代码实现
注意:我们是用数组来实现栈
说明:由于栈的实现较为简单,因此所有函数都封装好之后再一起测试
首先来完成准备工作:同样创建三个文件,Stack,c、Stack.h、test.c;
接着在 .h 文件中包含头文件及结构体的定义
cpp
//Stack.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int STDataType;
//定义栈结构体
typedef struct stack
{
STDataType* a; //动态数组
int top; //栈顶
int capacity; //容量
}Stack;
0、初始化
初始化就是将结构体中的指针置为空,栈顶和容量均值为0即可;
这样就代表我们的 top = 0 表示无元素;
因此判断需要扩容的条件就是 top == capacity
而如果将 top 初始化为 -1,即代表我们的 top == -1 表示无元素;
此时判断需要扩容的条件是 top + 1 == capacity;
两者初始化均可;
我们采用 top == 0 作为标准
cpp
//初始化
void STInit(Stack* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
1、入栈
分析逻辑:
我们需要结构体指针以及入栈元素x;
首先判断空间够不够;如果不够,则申请空间;
直接利用 top 表示栈顶元素进行插入即可
最后记得 top++
cpp
//入栈
void STPush(Stack* ps, STDataType x)
{
assert(ps);
//判断空间够不够
if (ps->top == ps->capacity)
{
//申请空间
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* newa = (STDataType*)realloc(ps->a,sizeof(STDataType) * newcapacity);
if (newa == NULL)
{
printf("realloc failed!\n");
return;
}
ps->a = newa;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
2、出栈
分析逻辑:
直接改变索引即可;即 top-- ;
cpp
//出栈
void STPop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
3、返回栈顶元素
分析逻辑:
直接返回下标为 top - 1 的元素即可;
cpp
//获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
return ps->a[ps->top - 1];
}
4、获取栈中有效元素个数
分析逻辑:
返回 top - 1 的值即可
cpp
//获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
5、检测栈是否为空
为空返回非0值,不为空返回0
分析逻辑:
判断 top 是否为0
cpp
//检测栈是否为空
bool StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
6、销毁栈
分析逻辑:
先 free 指针指向的空间,接着将指针置为空;
最后将 top 和 capacity 置为0即可;
cpp
//销毁栈
void StackDestroy(Stack* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
三、测试代码
我们在 test.c 文件中进行测试
1、测试入栈
cpp
void test()
{
Stack st;
StackInit(&st);
//入栈1 2 3 4 5
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
printf("\n");
StackDestroy(&st);
}
int main()
{
test();
return 0;
}
我们运行来看一下:

没有问题!
2、测试出栈
cpp
void test()
{
Stack st;
StackInit(&st);
//入栈1 2 3 4 5
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
StackPop(&st);
StackPop(&st);
StackPop(&st);
StackPop(&st);
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
printf("\n");
StackDestroy(&st);
}

出栈四次后,栈内还有一个元素1;
此时再执行两次出栈函数,看是否会引发断言

没有问题
3、测试获取栈顶元素

其实已经在入栈时测试过了
4、测试返回栈中有效元素个数

5、测试检测栈是否为空


如有不足之处恳请指出!!!