一.什么是栈?
栈是一种特殊的线性表,它只允许在一端进行插入元素和删除的操作。可以进行插入和删除的一端叫做栈顶,另一端叫做栈底。
二.栈的底层结构
链表和数组都可以作为栈的底层结构,相对而言数组更适合作为栈的底层结构,因为数组在尾上插入数据的代价比较小。
三.栈结构的定义
typedef int STDataType;
typedef struct Stack
{
STDataType* arr;//是结构体里的指针成员,保存动态数组的首地址,栈的数据就存在那个数组里。
int top;//有效元素数量。
int capacity;//栈的容量,是元素个数不是字节。
}ST;
四.栈的初始化
void StackInit(ST* ps)
{
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
五.入栈.
接受栈指针ps和待入栈元素x,先判断有效元素数量top和栈的容量capacity是否相等,若栈满就用realloc函数扩容(初始容量扩为4后续每次翻倍),扩容失败就打印错误并退出程序,罗容后更新栈的数组指针和容量,最后把元素x放到top下标位置,然后top在自增。
void StackPush(ST* ps, STDataType x)
{
if (ps->top == ps->capacity)
{
//增容
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));//总字节
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
ps->arr = tmp;//realloc函数的返回值-->返回新内存块的首地址。
ps->capacity = newCapacity;
}
//先把x放到top下标位置然后top++。
ps->arr[ps->top++] = x;
}
六.判断栈是否为空
bool StackEmpty(ST* ps)
{
//断言:防止空指针传入,ps为NULL直接报错。
assert(ps);
//top等于0代表栈没有有效元素,返回true(空),否则返回false(非空)。
return ps->top == 0;
}
七.出栈
先用断言判断栈不为空,防止对空栈进行出栈操作,出栈并不删除数组里的数据,只需将代表栈的个数的top变量前置减一,相当于把栈顶的有效元素范围向前收缩一位,然后出栈。
void StackPop(ST* ps)
{
//断言:栈不能为空。
assert(!StackEmpty(ps));
//然后在出栈。
--ps->top;
}
八.取栈顶元素
先用断言判断栈不为空,避免空栈读取数据,top代表下一个代存入元素的下标,所以栈顶的有效元素存放在下标top-1处,函数直接返回这个位置的数据,只读取栈顶的值,不会修改 top,也不会删除栈中的元素。
STDataType StackTop(ST* ps)
{
assert(!StackEmpty(ps));
return ps->arr[ps->top - 1];
}
九.获取栈的有效元素个数
int StackSize(ST* ps)
{
return ps->top;
}
十.销毁栈
void StackDestroy(ST* ps)
{
if (ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}