目录
一、定义
栈是一种特殊的线性变表,它只允许在固定的一端进行插入及删除操作。进行数据插入和数据删除的一端称为栈顶,另一端叫做栈底。栈中数据元素遵守后进先出的原则。
压栈:栈的插入操作
出栈:栈的删除操作
栈的实现可通过数组或者链表实现,相对来说,使用数组结构更加方便。因为数组是在尾部插入数据,代价较小。若使用链表,需要单独统计最后元素地址,比较麻烦。
二、程序实现
1、结构体声明
因为栈是一个数组,且不能确定会有多少数据进入栈内。因此可以通过动态开辟数组空间实现栈的扩容。并且,我们需要标记栈的容量大小与站内实际数据元素个数,栈的容量可以方便我们判断什么时候进行扩容。数据元素个数就是数组下标(指向最后一个元素的下一个位置),可以通过下标操作栈顶元素。
因此,我们声明栈时,使用结构体进行声明。结构体内具有指向数组的数组指针、数组容量、最后一个数据元素下标。
struct Stack{
StackDataType* arr;
int capacity;
int top;
};
2、对结构体初始化
实例化结构体stack,因为结构体内数据会需要改变,因此在传递参数时,需要传递结构体指针而非结构体本身。这样可以通过操作结构体指针改变结构体内数据。如果传递结构体对象,只是传递的结构体对象的复制,并不会改变结构体。因此在结构体初始化时,若需改变结构体内数据,传递结构体指针。
int main()
{
Stack stack; //实例化结构体
StackInit(&stack);//传递结构体指针
return 0;
}
初始化时,栈内还没有数据元素,因此栈可暂时开辟少量空间,等到栈内实际元素个数将要超出栈的容量时,再进行动态开辟数组空间。这里我们初始化容量capacity=4,top为指向数组元素的下一元素下标。容量为4时,数组下标最大为3。因此当top=4时(也就是capacity等于top时)要进行扩容。
void StackInit(Stack* ps)
{
assert(ps);
StackDataType* parr=(StackDataType*)malloc(sizeof(StackDataType)*4);//容量为4
if(parr==NULL){
printf("栈空间开辟失败");
}
ps->arr=parr;
ps->top=0;
ps->capacity=4;
}
3、插入数据
每插入一个数据,都需要判断top与capacity是否相等,若相等,需进行扩容,每次扩容,将容量扩大2倍。插入数据后,栈顶下标top加1。
void StackPush(Stack* ps,StackDataType x)
{
assert(ps);//测试不是空指针
if(ps->top==ps->capacity){
printf("栈已满,进行增容");
StackDataType* parr=(StackDataType*)realloc(ps->arr,sizeof(StackDataType)*ps->capacity*2);
if(parr==NULL){
printf("栈空间增容失败");
}
ps->arr=parr;
ps->capacity*=2;
}
ps->arr[ps->top]=x;
ps->top++;
}
4、删除数据
删除数据较为简单,直接将top减1即可。
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->top>0);
ps->top--;
}
5、释放空间
释放结构体内数组指针所指向的栈空间,将结构体内数组设为NULL,结构体容量及下标设为0。
void StackDestory(Stack* ps)
{
free(ps->arr);
ps->arr=NULL;
ps->top=ps->capacity=0;
}