链式栈初始化以及入栈出栈代码

整体设计思路
- 为了方便管理链式栈,我们创建了链式栈的节点以及管理结构体。其中管理结构体包含了栈顶的地址以及栈的大小(由于是链式结构因此不必提取申请一块固定大小的内存),栈节点结构体包含了数据域以及next指针。
- Note:在遍历整个链式栈的时候,必须必须必须创建一块临时的指针来保存栈顶的地址,为了防止在遍历过程中栈顶节点的丢失。例如我们如果不就行保存,在每次遍历之后必定会使用stack->top=stack->top->next,如果首这样,那么原来的那个栈顶节点的地址就会丢失。
代码展示
/********************************************************************************************************
*
* file name : 链式栈.c
* author : xu1234xcs@163.com
* data : 2025.5.12
* function : 该程序实现链式栈栈元素的增删改查,目的是提高设计程序的逻辑思维
* note : 为了提高可移植性,所以链式栈中元素的数据类型为DataType_t,用户可以根据实际情况修 改链式表中元素的类型。
* 另外,为了方便管理链式栈,所以用户设计LinkStack_t结构体,该结构体中包含两个成员: 栈容量+栈顶元素的地址
* 对于单个链节点的结构体,该结构体中包括数据域以及其next地址
*
* Copyright (c) 2024-2025 xu1234xcs@163.com@163.com All right Reserved
* ******************************************************************************************************/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
// 指的是链式栈中的元素的数据类型,用户可以根据需要进行修改
typedef int DataType_t;
// 链式栈节点结构
typedef struct StackNode
{
DataType_t data; // 存储栈中元素的数据域
struct StackNode *next; // 指向下一个节点的指针(栈的下一层)
} StackNode_t;
// 构造记录链式栈LinkStack各项参数(栈顶地址+栈容量)的结构体
typedef struct LinkStack
{
StackNode_t *Top; // 记录栈顶地址
unsigned int Size; // 记录栈容量
} LinkStack_t;
// 创建链式栈进行初始化
LinkStack_t *LinkStack_Create()
{
// 1.利用calloc为链式栈的管理结构体申请一块堆内存
LinkStack_t *Manager = (LinkStack_t *)calloc(1, sizeof(LinkStack_t));
if (NULL == Manager)
{
perror("calloc memory for manager is failed");
exit(-1); // 程序异常终止
}
// 2.对管理链式栈的结构体进行初始化(元素容量 + 最后元素下标)
Manager->Size = 0; // 对链式栈中的容量进行初始化
Manager->Top = NULL; // 由于链式栈为空,则栈顶元素的下标初值为NULL
return Manager;
}
// 初始化一个新的栈节点
StackNode_t *StackNode_Create(DataType_t data)
{
// 1.利用calloc为链式栈的新节点申请一块堆内存
StackNode_t *new = (StackNode_t *)calloc(1, sizeof(StackNode_t));
if (NULL == new)
{
perror("calloc memory for manager is failed");
exit(-1); // 程序异常终止
}
// 2.对管理链式栈的新节点进行初始化(元素容量 + 最后元素下标)
new->data = data;
new->next = NULL;
return new;
}
// 入栈
bool LinkStack_Push(LinkStack_t *Manager, DataType_t Data)
{
// 1.为新节点分配堆内存并进行初始化
StackNode_t *new = StackNode_Create(Data);
if (NULL == new)
{
perror("calloc memory for manager is failed");
exit(-1); // 程序异常终止
}
// 2.如果节点创建成功,则把新元素添加到链式栈的栈顶
new->next = Manager->Top;
Manager->Top = new;
Manager->Size++;
return true;
}
// 判断链式栈是否为空
bool LinkStack_IsEmpty(LinkStack_t *Manager)
{
return (NULL == Manager->Top) ? true : false;
}
// 出栈
DataType_t LinkStack_Pop(LinkStack_t *Manager)
{
// 1.判断链式栈是否为空
if (LinkStack_IsEmpty(Manager))
{
printf("LinkStack is Empty!\n");
return;
}
// 2.由于删除了一个元素,则需要让链式栈的栈顶元素下标指向下一个
StackNode_t *temp = Manager->Top;//备份栈顶元素的地址 方便在进行指针偏移后free操作 不然在进行偏移后 会导致之前首节点的地址丢失
DataType_t data = temp->data;
Manager->Top = temp->next;
free(temp);
Manager->Size--;
return data;
}
// 遍历链式表的元素
void LinkStack_Print(LinkStack_t *Manager)
{
StackNode_t *current = Manager->Top;
printf("栈中的元素为: ");
while (current != NULL)
{
printf("%d ", current->data); // 访问数据域
current = current->next; // 移动到下一个节点
}
printf("\n");
}
int main(int argc, char const *argv[])
{
LinkStack_t *stack = LinkStack_Create();
LinkStack_Push(stack, 10);
LinkStack_Push(stack, 20);
LinkStack_Push(stack, 30);
LinkStack_Print(stack);
printf("弹出元素: %d\n", LinkStack_Pop(stack));
LinkStack_Print(stack);
return 0;
}
测试结果展示
