1、栈
1.1 栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
我们以生活中的事物来理解一下栈:糖葫芦
串糖葫芦的时候是最后一颗糖葫芦先串进去,但是我们吃的第一个却是最后一颗被串上去的。
2、栈的实现
栈的实现一般可以使用 数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的
代价比较小。 我们本篇文章就是使用数组来实现栈。
2.1 接口
#include <stdio.h> #include <stdlib.h> #include <assert.h> // 支持动态增长的栈 typedef int STDataType; typedef struct Stack { STDataType* a; int top; // 栈顶 int capacity; // 容量 }Stack; // 初始化栈 void StackInit(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);
3、接口的实现
3.1 初始化
我们的栈开始是空的,因此容量与栈顶赋值为 0。
我们也可以将栈顶赋值为-1,入栈的时候先让栈顶指针++,再将元素入栈,这样栈顶指针正好指向的就是栈顶元素。但是我们这里还是将栈顶指针赋值为 0 了,这样在获取栈中有效元素的时候就不用再操作了,为后面提供了便利。
void StackInit(Stack* ps) { assert(ps); ps->a = NULL; //ps->top = -1;//top 指栈顶数据 ps->top = 0;//top 指栈顶数据的下一个位置 ps->capacity = 0; }
3.2 入栈/压栈
在入栈前我们要先判断栈是否满了,如果满了我们就给栈先进性扩容。我们这里没有开始先malloc空间,而是第一次就使用了 realloc,这里有一个技巧,那就是用三目操作符先看容量是否为 0 ,如果是 0 ,那么就意味着是第一次开空间,就给 newcapacity 赋值为 4,不为 0就说明是扩容,那就将新的容量扩容为之前的 2 倍。
判满后我们就入栈,这里其实就是给数组里面放元素进去,给栈顶位置放一个元素进去后让 ps->top++,往后走一步。
void StackPush(Stack* ps, STDataType data) { assert(ps); if (ps->capacity == ps->top) { int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity); if (tmp == NULL) { perror("realloc fail:"); return; } ps->a = tmp; ps->capacity = newcapacity; } ps->a[ps->top] = data; ps->top++; }
3.3 出栈
出栈很简单,让 ps->top--就好了,下次入栈的元素就会将之前的元素覆盖掉。
void StackPop(Stack* ps) { assert(ps); assert(!StackEmpty(ps)); ps->top--; }
3.4 获取栈顶元素
获取栈顶元素前需要判空,如果是空的话就不存在栈顶指针。栈顶元素就是下标为 top-1 的元素,所以返回 ps->[ps->top-1] 就是栈顶元素。
STDataType StackTop(Stack* ps) { assert(ps); assert(!StackEmpty(ps)); return ps->a[ps->top-1]; }
3.5 获取栈中有效元素个数
因为下标 top 是栈顶元素的下一个位置,所以返回 top 就是栈中的有效元素个数。
int StackSize(Stack* ps) { assert(ps); return ps->top; }
3.6.1 bool 类型接口
int StackEmpty(Stack* ps) { assert(ps); return ps->top == 0; }
3.6.2 int 类型接口
这里我们约定好为空返回 非0,不为空返回 0。
int StackEmpty(Stack* ps) { assert(ps); if (0 == ps->top) return 1; else return 0; }
3.7 销毁栈
释放数组并置空,将容量与栈顶赋值为 0。
void StackDestroy(Stack* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = 0; ps->top = 0; }
4、完整代码
完整代码在代码仓库,入口:C语言: C语言学习的代码,多复习 - Gitee.com