目录
认识栈的结构(后进先出):
栈:拿取数据和添加数据都在栈顶的一种数据结构。
我们可以生动地把栈看做一个羽毛球桶。我从桶顶放入羽毛球我就只能先拿刚放进去的羽毛球。
栈这个数据结构也是如此,栈中添加数据只能从栈顶添加,拿取(删除或读取)数据也只能在栈顶中拿取数据。而这样一种只能从结构的尾部进行插入删除操作的一种数据结构我们适合用顺序表来进行实现,顺序表不适合头部的增删数据操作,比较适合尾部的增删数据操作,所以栈这一数据结构我们可以用顺序表来进行实现。
#pragma once
#include <stdio.h>
#include <assert.h>
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
栈的常用接口:
// 初始化栈
void StackInit(Stack* ps);
// 检查空间,如果满了,进行增容
void CheckCapacity(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
初始化栈:
栈的初始化方法和顺序表的初始化方法一样,不过多赘述,直接代码奉上。(这个方法不会的友友,可以去我的顺序表篇去补一下,顺序表讲的十分详细)
void StackInit(Stack* ps)
{
ps->_a = (STDataType*)malloc(4 * sizeof(STDataType));
ps->_top = 0;
ps->_capacity = 4;
}
检查空间,如果满了,进行增容:
扩容方法与顺序表相同,不过多赘述,直接代码奉上。(这个方法不会的友友,可以去我的顺序表篇去补一下,顺序表讲的十分详细)
// 检查空间,如果满了,进行增容
void CheckCapacity(Stack* ps)
{
if (ps->_top == ps->_capacity)
{
int newcapacity = ps->_capacity * 2;
ps->_a = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));
ps->_capacity = newcapacity;
}
}
入栈:
入栈和顺序表尾插的逻辑一样,直接代码奉上。
// 入栈
void StackPush(Stack* ps, STDataType data)
{
CheckCapacity(ps);
ps->_a[ps->_top] = data;
ps->_top++;
}
出栈:
出栈和顺序表尾删的逻辑一样,直接代码奉上。
// 出栈
void StackPop(Stack* ps)
{
ps->_top--;
}
获取栈顶元素 :
获取栈顶元素相当于获取顺序表中的最后一个元素。
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
return ps->_a[ps->_top - 1];
}
获取栈中有效元素个数:
int StackSize(Stack* ps)
{
return ps->_top;
}
检测栈是否为空,如果为空返回非零结果,如果不为空返回0 :
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
return !(ps->_top);
}
销毁栈 :
// 销毁栈
void StackDestroy(Stack* ps)
{
free(ps->_a);
ps->_a = NULL;
ps->_top = ps->_capacity = 0;
}
致谢:
整体而言,实现栈这个数据结构并不难,重要的是掌握顺序表中的增删查改的方法,以及之后一些常见oj题中利用栈这个数据结构来解决问题的方法,还有之后的利用栈由递归代码变为非递归代码的实现才是重难点。这些问题我会留到之后的文章中进行详细地讲解,不要错过哦。
感谢观看!!!