栈
栈的概念
- 栈是数据结构重要的思想,在数据结构中,有两种方式来存储数据
-
- 链式结构和顺序结构,
下面会有链式结构和顺序结构分别存储的例子
以顺序结构举例:
栈遵循后进先出的规则LIFO(Last Input First Output ),栈只能在一端进行操作
- 插入元素:入栈(
Push)、压栈。 - 取出元素:出栈(
Pop)、弹栈。
由于栈只能在一端操作,所以在操作的那一端叫做栈顶(Top),另外一端叫做栈底(Bottom)
没有数据的栈叫做空栈。

顺序存储栈(顺序栈)
-
在使用栈的时候需要注意在哪一端操作,如果是顺序表来实现栈,那么在尾部操作是最好的。
-
栈尾就是顺序表头部,栈顶顺序表的尾部。
-
实现顺序栈和顺序表一样需要有管理者

//这个存储的数据类型是可以修改的,遍历输出的时候需要修改输出的转换符
//顺序栈存放的数据类型
typedef int DataType_t;
//1.需要建立顺序栈的管理结构体
typedef struct seqstack
{
DataType_t * Bottom; //顺序栈的首地址
unsigned int Size; //顺序栈的容量
int Top; //顺序栈的存储个数
}SeqStack_t;
创建顺序栈
/****************************************************
* 函数名称: SeqStack_Create
* 函数功能: 新建顺序栈
* 函数参数:
* @size:创建顺序栈的大小
* 返回结果: 返回顺序栈管理者的地址
* 注意事项: None
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
SeqStack_t * SeqStack_Create(unsigned int size)
{
//1.首先需要一个管理者
SeqStack_t * Manager = (SeqStack_t *)calloc(1,sizeof(SeqStack_t));
if(NULL == Manager){
perror("calloc for Manager is failed!!!");
exit(-1);
}
//2.建立顺序栈的堆空间,堆空间的首地址由管理者的addr成员管理
Manager->Bottom = (DataType_t*) calloc(size,sizeof(DataType_t));
if(NULL == Manager->Bottom){
perror("calloc for Manager is failed!!!");
free(Manager);
Manager = NULL;
exit(-1);
}
//3.顺序栈创建完成需要初始化
Manager->Size = size;
//元素的下标从-1开始表示没有元素
Manager->Top = -1;
return Manager;
}
入栈
- 在入栈之前需要判断栈是否已满

/****************************************************
* 函数名称: SeqStack_IsFull
* 函数功能: 判断顺序栈是否已满
* 函数参数:
* @Manager:顺序栈管理者的地址
* 返回结果: true:已满。false:未满。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool SeqStack_IsFull(SeqStack_t * Manager)
{
return (Manager->Top+1 == Manager->Size) ? true : false ;
}
/****************************************************
* 函数名称: SeqStack_TailPushEle
* 函数功能: 给顺序栈尾部添加新的元素
* 函数参数:
* @Manager:顺序栈管理者的地址
* @data :添加的数据
* 返回结果: true:添加成功。false:添加失败。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool SeqStack_TailPushEle(SeqStack_t * Manager,DataType_t data)
{
//1.首先判断顺序栈是否已满
if( SeqStack_IsFull(Manager) ){
printf("sequence stack is full!\n");
return false;
}
//2.未满可以插入,在尾部插入,插入完成之后也需要个数需要加一
Manager->Bottom[++Manager->Top] = data;
return true;
}
出栈
- 在入栈之前需要判断栈是否为空

/****************************************************
* 函数名称: SeqStack_IsEmpty
* 函数功能: 判断顺序栈是否为空
* 函数参数:
* @Manager:顺序栈管理者的地址
* 返回结果: true:为空。false:不为空。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool SeqStack_IsEmpty(SeqStack_t * Manager)
{
return (Manager->Top == -1) ? true : false ;
}
/****************************************************
* 函数名称: SeqStack_TailPopEle
* 函数功能: 在顺序栈的尾部取元素
* 函数参数:
* @Manager:顺序栈管理者的地址
* 返回结果: 返回删除的数据(需要取出),没有返回值代表没取出来
* 注意事项: None
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
DataType_t SeqStack_TailPopEle(SeqStack_t * Manager)
{
//1.首先需要顺序栈是否为空
if(SeqStack_IsEmpty(Manager)){
printf("sequence stack is empty!\n");
return ;
}
//存储需要返回的数据
DataType_t temp = Manager->Bottom[Manager->Top];
Manager->Top--;
return temp;
}
遍历输出栈
/***************************************************
* 函数名称: SeqStack_TraEle
* 函数功能: 遍历输出每一个元素
* 函数参数:
* @Manager :顺序栈管理者的地址
* 返回结果: true:遍历成功。false:遍历失败。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/04/20
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool SeqStack_TraEle(SeqStack_t * Manager)
{
//1.首先需要顺序栈是否为空
if(SeqStack_IsEmpty(Manager)){
printf("sequence stack is empty!\n");
return false;
}
//2.直接访问元素
for(int i = 0;i <= Manager->Top;i++){
printf("%d element is %d\n",i+1,Manager->Bottom[i]);
}
return true;
}
删除栈
/***************************************************
* 函数名称: SeqStack_Dle
* 函数功能: 删除顺序栈
* 函数参数:
* @Manager :顺序栈管理者的地址
* 返回结果: true:删除成功。false:删除失败。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/04/20
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool SeqStack_Dle(SeqStack_t * Manager)
{
//1.判断管理者是否存在
if(NULL == Manager){
printf("sequence stack is not exist");
return false;
}
//2.先把顺序栈删除,在删除管理者
free(Manager->Bottom);
Manager->Bottom = NULL;
free(Manager);
Manager = NULL;
return true;
}
需要的头文件
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
链式存储栈(链栈)
-
使用单向不循环链表来实现栈
-
在使用栈的时候需要注意在哪一端操作,如果是链表来实现栈,那么在头部操作是最好的。
-
栈尾就是链表尾部,栈顶链表的头部。
-
栈的节点

//链栈节点下面是数据的数据类型
typedef char DataType_t;
//带头结点的链栈
//1.每一个节点都有自己的元素和连接下一个元素的地址
typedef struct linkstack
{
DataType_t data; //链栈节点存放的数据
struct linkstack *next; //链栈节点存放下一个链栈节点的地址
}LkStack_t;

创建的栈
/***************************************************
* 函数名称: LkStack_CreatList
* 函数功能: 创建一个新的链栈
* 函数参数: None
* 返回结果: 返回链栈的地址:创建成功。NULL:创建失败。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
LkStack_t * LkStack_CreatList(void)
{
//在堆空间申请一个空间存放链栈的头结点
LkStack_t * Head = (LkStack_t *)calloc(1,sizeof(LkStack_t));
if(NULL == Head){
perror("calloc memory for head is failed!!!");
return NULL;
}
//头结点的初始化,数据不需要初始化
Head->next = NULL;
//返回头结点的地址
return Head;
}
/***************************************************
* 函数名称: LkStack_NewNode
* 函数功能: 创建一个链栈新的节点
* 函数参数:
* @data :创建链栈节点时,下面存放的数值
* 返回结果: 返回链栈的地址:创建成功。NULL:创建失败。
* 注意事项: 一般都在插入的时候需要使用,不会单独使用
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
LkStack_t * LkStack_NewNode(DataType_t data)
{
//1.先从堆空间申请内存存放链栈节点
LkStack_t * New = (LkStack_t *)calloc(1,sizeof(LkStack_t));
if(NULL == New){
perror("Calloc memory for NewNode is failed!");
return NULL;
}
//初始化链栈节点
New->data = data;
New->next = NULL;
//申请成功直接返回
return New;
}
入栈

/***************************************************
* 函数名称: LkStack_HeadPushNode
* 函数功能: 在头节点的后面插入新的节点
* 函数参数:
* @Head :头结点的地址
* @data :创建链栈节点时,下面存放的数值
* 返回结果: true:插入成功;false:插入失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkStack_HeadPushNode(LkStack_t * Head,DataType_t data)
{
//1.先判断链栈是否存在
if(NULL == Head){
printf("Linkstack head is not exist!!!\n");
return false;
}
//创建新的节点
LkStack_t * New = LkStack_NewNode(data);
if(NULL == New){
return false;
}
//如果存在,直接把头结点指向的地址赋值给新的节点下面的地址
New->next = Head->next;
Head->next = New;
return true;
}
出栈

- 在出栈之前需要判断栈是否为空
/***************************************************
* 函数名称: LkStack_IsEmpty
* 函数功能: 判断链栈是否为空
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:为空;false:不为空
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkStack_IsEmpty(LkStack_t * Head)
{
return (Head->next == NULL) ? true : false;
}
/***************************************************
* 函数名称: LkStack_HeadPopNode
* 函数功能: 把链栈的首结点取出
* 函数参数:
* @Head :头结点的地址
* 返回结果: 返回取出的数据;没有值取出失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
DataType_t LkStack_HeadPopNode(LkStack_t * Head)
{
//1.先判断链栈是否存在
if(NULL == Head){
printf("Linkstack head is not exist!!!\n");
return;
}
//判断链栈是否为空
if(LkStack_IsEmpty(Head)){
printf("Linkstack is empty!!!\n");
return;
}
//定义变量存储当前结点直接让他指向首节点的地址,以便于释放删除的结点
LkStack_t *Phead = Head->next;
DataType_t temp = Phead->data;
//寻找到数据节点可以开始删除
Head->next = Phead->next;
Phead->next = NULL;
free(Phead);
Phead = NULL;
return temp;
}
遍历输出栈
/***************************************************
* 函数名称: LkStack_TraNode
* 函数功能: 遍历输出每一个结点的数据
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:遍历成功;false:遍历失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkStack_TraNode(LkStack_t * Head)
{
//1.先判断链栈是否存在
if(NULL == Head){
printf("Linkstack head is not exist!!!\n");
return false;
}
//判断链栈是否为空
if(LkStack_IsEmpty(Head)){
printf("Linkstack is empty!!!\n");
return false;
}
//备份数据,直接给首结点数据
LkStack_t * Phead = Head->next;
int i = 1;//输出第几个数据
//遍历到最后的节点,输出数据
while(Phead->next){
printf("[%d]th Node is %c\n",i,Phead->data);
i++;
Phead = Phead->next;
}
printf("[%d]th Node is %c\n",i,Phead->data);
return true;
}
删除栈
/***************************************************
* 函数名称: LkStack_Del
* 函数功能: 删除链栈
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:删除成功;false:删除失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/05/02
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkStack_Del(LkStack_t * Head)
{
//1.先判断链栈是否存在
if(NULL == Head){
printf("Linkstack head is not exist!!!\n");
return false;
}
//让Head先向前走,然后后面跟着Head的前驱节点,删除前驱节点
LkStack_t * Head_prev = Head;
Head = Head->next;
//遍历到最后的节点,输出数据
while(Head){
//Head不为空直接删除直接前驱,
Head_prev->next = NULL;
free(Head_prev);
Head_prev = Head;
Head = Head->next;
}
//Head为空,退出去删除直接前驱和Head本身.
Head_prev->next = NULL;
free(Head_prev);
Head_prev = NULL;
return true;
}
需要的头文件
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

浙公网安备 33010602011771号