->Gitee源码点击这里<-
之前所实现的顺序表和链表都成为线性表,即他们的从逻辑上来看是连续的,线性的,按顺序的。
栈是一种特殊的线性表,其实现要基于顺序表或者链表,相比之下用顺序表来实现更优;
而和顺序表区别在于,栈不支持随机位置的数据插入和删除,入栈的数据遵循后进先出的原则。
栈的逻辑结构示意图:
接下来我们使用顺序表来实现一个栈。
首先定义一个结构体,该结构体包含了栈的相关信息:
typedef int STDatatype;
typedef struct Stack
{
STDatatype* a; //指向动态开辟的栈
int top = 0; //栈顶
int capacity = 0;//栈容量
};
接着对栈进行初始化
void StackInit(Stack* pst)
{
pst->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);//给定栈的初始大小
if (pst->a == NULL)
{
printf("Init Failed\n");
exit(-1);
}
pst->top = 0;
pst->capacity = 4;
}
栈在处理数据时,只需要两个接口即可,即入栈接口和出栈接口。入栈接口的本质就是顺序表的尾插;出栈接口的本质就是顺序表的尾删
一、入栈接口
void StackPush(Stack* pst, STDatatype data)
{
assert(pst);
//查询栈是否已满
if (pst->top == pst->capacity)
{
Stack* newa = (STDatatype*)realloc(pst->a, sizeof(STDatatype) * pst->capacity * 2);
if (newa == NULL)
{
printf("realloc failed\n");
exit(-1);
}
pst->a = newa;
pst->capacity *= 2;
}
pst->a[pst->top] = data;
pst->top++;
}
二、出栈接口
这里要注意,栈为空时,出栈接口不希望被调用
所以我们先设计一个判断栈是否为空的接口
bool StackIsEmpty(Stack* pst)
{
assert(pst);
return pst->top == NULL;
}
接着在出栈接口中,借助判空接口添加断言
void StackPop(Stack* pst)
{
assert(pst);
assert(!StackIsEmpty(pst)); //调用删除接口栈不能为空
pst->top--;
}
三、获取栈顶元素
STDatatype StackTop(Stack* pst)
{
assert(pst);
assert(!StackIsEmpty(pst));
return pst->a[pst->top - 1];
}
四、栈中有效元素的个数
int StackSize(Stack* pst)
{
assert(pst);
return pst->top;
}
五、栈的销毁
不要忘记,栈时动态开辟的,使用完毕要销毁空间
void StackDestroy(Stack* pst)
{
free(pst->a);
pst->capacity = 0;
pst->top = 0;
}
对于栈的一些说明:
对于栈,不设计打印接口,若想通过打印来看到栈中数据,需要使用StackTop()
获取栈顶元素接口和StackPop()
出栈接口,获取栈顶元素,打印,然后删除该栈顶元素,如此循环,当所有元素被打印时,栈已经为空了:
//栈中已经依次入栈1,2,3,4
//打印栈中元素
int main()
{
Stack mystack;
StackInit(&mystack);
while (!StackIsEmpty(&mystack))
{
printf("%d ", StackTop(&mystack));
StackPop(&mystack);
}
StackDestroy(&mystack);
}