数据结构与算法——栈的原理及C语言底层实现
参考博文: 【数据结构与算法】程序内功篇四–栈
栈的理论知识
- 栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈)
- 允许进行操作的一端称为“栈顶”,另一固定端称为“栈底”
- 当栈中没有元素时称为“空栈”
- 栈的特点 :后进先出(LIFO)
顺序栈的实现
1. 顺序栈的原理
它是顺序表的一种,具有顺序表同样的存储结构,由数组定义,配合用数组下标表示的栈顶指针top(相对指针)完成各种操作。
定义栈
typedef int data_t; //定义栈中数据元素类型
//栈的定义
typedef struct{
data_t * data; //指针指向栈的存储空间
int maxlen; //当前栈的最大元素个数
int top; //指示栈顶位置
}sqStack;
2. 栈的创建
//创建栈
sqStack* stack_create(int len)
{
sqStack * stack; //定义栈 stack
//为栈开辟空间
stack = (sqStack*)malloc(sizeof(sqStack));
if(stack == NULL)
{
printf("malloc sqstack faile\n");
return NULL;
}
//为栈内数据开辟空间
stack->data = (data_t *)malloc(sizeof(data_t) * len);
if(stack->data == NULL)
{
printf("malloc data faile\n");
return NULL;
}
//初始化数据
memset(stack->data, 0, len * sizeof(data_t));
stack->top = -1; //设置栈顶下标-1
stack->maxlen = len; //设置栈最大长度
return stack;
}
3. 数据入栈与出栈
数据出入栈原理图:
3.1 数据入栈
//入栈 -1: 入栈失败 0 : 入栈成功
int stack_push(sqStack* s, data_t value)
{
//入口参数检查
if(s == NULL){
printf("stack is NULL\n");
return -1;
}
//栈满
if(s->top == s->maxlen - 1){
printf("stack is full\n");
return -1;
}
//数据入栈
s->top++; //栈顶下标+1
s->data[s->top] = value;//在栈顶存入数据
return 0;
}
3.2 数据出栈
//出栈
int stack_pop(sqStack* s)
{
//入口参数检查
if(s == NULL){
printf("s is NULL\n");
return -1;
}
s->top--; //栈顶下标-1
return s->data[s->top+1]; //返回栈顶元素
}
4. 获取栈顶数据
//获取栈顶元素
data_t stack_top(sqStack* s)
{
if(s->top == -1)
printf("栈为空\n");
return s->data[s->top]; //获取栈顶元素的值
}
5. 判断是否为空栈或满栈
5.1 判断栈是否为空
//判断空栈
/*
1: 空栈
0: 非空栈
-1: 参数为空
*/
int stack_empty(sqStack * s)
{
//入口参数检查
if(s == NULL){
printf("s is NULL\n");
return -1;
}
if(s->top == -1) //栈为空
return 1;
else
return 0;
}
5.2 判断栈是否已满
//判断满栈
/*
1: 满栈
0:非满栈
-1:参数错误
*/
int stack_full(sqStack * s)
{
//入口参数检查
if(s == NULL){
printf("s is NULL\n");
return -1;
}
if(s->top == s->maxlen-1) //栈满
return 1;
else
return 0;
}
6. 清空栈数据
//清空栈
void stack_clear(sqStack * s)
{
//入口参数检查
if(s == NULL){
printf("s is NULL\n");
}
s->top = -1; //将栈顶下标设置为-1, 代表栈为空
}
7. 释放栈空间
//释放空间
int stack_free(sqStack * s)
{
free(s->data); //释放栈内部成员变量
free(s); //释放栈空间
}
8. 主流程测试程序
int main()
{
sqStack * s;
s = stack_create(10);
if(s == NULL)
return -1;
//入栈
stack_push(s,1);
stack_push(s,2);
stack_push(s,3);
stack_push(s,4);
while(stack_empty(s) == 0) //栈不为空
{
printf("pop: %d\n",stack_pop(s)); //出栈
}
stack_free(s); //释放栈
return 0;
}
链式栈的实现
1. 链式栈原理
插入操作和删除操作均在链表头部进行,链表尾部就是栈底,栈顶指针就是头指针。
typedef int data_t; //定义栈中数据元素类型
//栈的定义
typedef struct node_t{
data_t data; //节点数据域
struct node_t *next; //节点指针域
}linkStack; //定义链式栈
2. 数据入栈(头插法)
链式在的数据入栈相当于就是链表头插法插入节点
//入栈 -1: 入栈失败 0 : 入栈成功
int stack_push(linkStack* s, data_t value)
{
//入口参数检查
if(s == NULL){
printf("stack is NULL\n");
return -1;
}
//为新节点开辟空间 封装节点
linkStack * p = (linkStack *)malloc(sizeof(linkStack));
if(p == NULL)
{
printf("malloc p failed\n");
return -1;
}
p->data = value;
//节点插入链表 头插法
p->next = s->next;
s->next = p;
return 0;
}
3. 数据出栈
//出栈 -1:出栈失败 0:出栈成功
int stack_pop(linkStack* s)
{
//入口参数检查
if(s == NULL){
printf("s is NULL\n");
return -1;
}
data_t t;
linkStack * temp = s->next; //存储待删除的节点
s->next = s->next->next; //指向下下个节点
t = temp->data; //获取节点的值
free(temp); //释放出栈的节点
temp = NULL;
return t;
}
4. 判断是否为空栈
//判断空栈
/*
1: 空栈
0: 非空栈
-1: 异常
*/
int stack_empty(linkStack * s)
{
if(s == NULL)
{
printf("s is NULL\n");
return -1;
}
if(s->next == NULL)
return 1;
else
return 0;
}
5. 获取栈顶元素
//获取栈顶元素
data_t stack_top(linkStack* s)
{
if(s == NULL)
printf("s is NULL\n");
return s->next->data;
}
6. 释放栈空间
通过依次遍历链表的方式释放栈内存
//释放栈空间
linkStack* stack_free(linkStack * s)
{
if(s == NULL)
{
printf("s is NULL\n");
return NULL;
}
linkStack * p = s;
while(s != NULL) //依次遍历整个链表 进行删除
{
p = s; //暂存s
s = s->next; //s偏移
printf("free: %d\n",p->data);
free(p); //释放暂存s
}
return NULL;
}
7. 主流程测试程序
int main()
{
linkStack * s;
s = stack_create(); //创建栈
if(s == NULL) //创建栈失败
return -1;
//入栈
stack_push(s,1);
stack_push(s,2);
stack_push(s,3);
stack_push(s,4);
/*
while(!stack_empty(s)) //栈不为空
{
printf("pop: %d\n",stack_pop(s)); //出栈
}
*/
s = stack_free(s); //释放栈,并避免s出现野指针
return 0;
}