上次结束了链表部分的内容:链接未来:深入理解链表数据结构(二.c语言实现带头双向循环链表)
然而,当我们涉及特定问题时,另一个非常有用的数据结构也开始显得至关重要——栈
栈与链表有着截然不同的特性,它采用一种后进先出(LIFO)的策略,这意味着最后进入栈的元素将首先被取出。这样的特性赋予了栈在特定场景下独特的价值和功能
源码可以去我的gitee:Nero的gitee
文章目录
- 1.栈的概念和结构
- 2.栈的实现
- 2.1项目文件规划
- 2.2基本结构及各功能(Stack.h)
- 2.3各功能具体实现
- 初始化
- 插入
- 删除
- 返回栈顶元素
- 是否为空
- 元素数量
1.栈的概念和结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则
压栈(push):栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈(pop):栈的删除操作叫做出栈。出数据也在栈顶
2.栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。栈只在一端进行插入和删除,选择数组尾端非常契合。
2.1项目文件规划
-
- 头文件Stack.h:用来基础准备(常量定义,typedef),链表表的基本框架,函数的声明
- 源文件Stack.h:用来各种功能函数的具体实现
- 源文件test.c:用来测试功能是否有问题,进行基本功能的使用
2.2基本结构及各功能(Stack.h)
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>typedef int STDataType;typedef struct Stack
{int* a;int top; // 标识栈顶位置的int capacity; //栈的容量
}ST;void STInit(ST* ps);//初始化
void STDestroy(ST* ps);//销毁void STPush(ST* ps, STDataType x);// 栈顶插入
void STPop(ST* ps);// 栈顶删除STDataType STTop(ST* ps);//返回栈顶元素bool STEmpty(ST* ps);//判断栈是否为空int STSize(ST* ps);//栈中元素数量
2.3各功能具体实现
初始化
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = -1;//我选择了-1ps->capacity = 0;
}
top用来标记栈顶位置,那一开始初始化为多少合适:
- 初始化为**-1**:指向塔顶元素。因为底层用数组来实现,那第一个元素下标为0,一开始无元素为-1,有了第一个元素加上1变成0,完全符合。
- 初始化为0:指向塔顶元素的下一个位置。道理同上,但是总是比塔顶元素下标大1
插入
void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top + 1)//判断有没有满{int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* new = (STDataType*)realloc(ps->a, sizeof(ST) * newCapacity);assert(new);ps->a = new;ps->capacity = newCapacity;}ps->top++;ps->a[ps->top] = x;
}
代码确保传入的栈指针
ps
是有效的。然后,它检查栈是否已满。当栈满时,需要扩展栈的容量栈的
top
指针增加,表示栈顶位置上移一个单位。最后,要推入栈的元素x
被放入栈顶位置
ps->a[ps->top]
删除
void STPop(ST* ps)
{assert(ps);assert(ps->top >= 0);//确保不为空ps->top--;
}
返回栈顶元素
STDataType STTop(ST* ps)
{assert(ps);assert(ps->top >= 0);return ps->a[ps->top];
}
是否为空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == -1;
}
元素数量
int STSize(ST* ps)
{assert(ps);return ps->top + 1;
}
大家一般都是:栈和队列,栈和队列,(二者放在一起)马上就到队列的知识梳理了。
感谢大家支持!!!