1、栈的概念和结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈,出数据也在栈顶。
2、栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
下面代码是定长的静态栈的结构,但在实际应用中较少使用。
typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType a[N];
int top;//栈顶
}Stack;
动态栈的结构在日常开发中使用较多,本节将对动态栈进行详细说明:
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
初始化时,栈中属性a
在堆中开辟一块4*sizeof(STDataType)
的空间,同时给top
赋值0,capacity
赋值4。
void StackInit(ST* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
if (ps->a == NULL)
{
perror("malloc fail");
exit(-1);
}
ps->top = 0;
ps->capacity = 4;
入栈,首先判断a
是否存满,符合条件ps->top == ps->capacity
时,表明a
已经存满,此时重新在堆中开辟一块空间以替代旧的a
的空间;若a
有空,则直接将要插入的值x
直接压栈进入pa->a[pa->top]
。
void StackPush(ST* ps,STDataType data)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDataType* tmp = realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
出栈比较容易,出栈一次,就top-1
。
void StackPop(ST* ps)
{
assert(ps);
assert(ps->a > 0);
return ps->a[ps->top - 1];
}
获取栈顶元素
STDataType StackTop(ST* ps)
{
assert(ps);
assert(ps->a > 0);
ps->top--;
}
获取栈中有效元素个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
检测栈是否为空,如果为空返回非0结果,如果不为空返回0
int StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
销毁栈,详见说明请参考动态内存管理:
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
3、调试
void TestStack1()
{
ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
printf("size:%d\n", StackSize(&st));
printf("size:%d\n", st.top);
StackPop(&st);
StackPop(&st);
StackPop(&st);
printf("%d\n", StackTop(&st));
StackDestroy(&st);
}
初始化栈后的栈结构属性值:
5次压栈后,栈内结构属性值:
此时,top
的值为5。最后,销毁栈时,释放堆中的空间,将存储在a
的空间首元素地址NULL。
详细的代码详见:动态栈