栈的链式存储结构,简称链栈。
栈只能从栈顶来作插入和删除动作,由于链表有头指针,而栈顶指针也是必须的,所以比较好的方法是把栈顶放在链表的头部。另外,都已经有了栈顶在链表头部了,单链表中比较常用的头节点也就失去了意义,通常对于链栈来说,是不需要头结点的。
对于链栈来说,基本不会存在栈满的情况,除非内存已经没有可用的使用空间,如果发生则计算机系统将死机崩溃,而不是链栈是否溢出的问题。
对于空栈来说,链表原定义的头指针指向空,那么链栈的空其实就是 top=NULL。
定义栈结构以及操作:
#ifndef _LINK_STACK_H_
#define _LINK_STACK_H_
/*栈数据类型*/
typedef void LinkStack;
#pragma region 栈基本操作函数原型
/****************************************************
创建一个空的链式栈
--------------------------------------------------
参数 :void
返回值 :LinkStack* | NULL
****************************************************/
LinkStack* LinkStack_Create();
/****************************************************
释放栈空间
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 :void
****************************************************/
void LinkStack_Destroy(LinkStack* stack);
/****************************************************
清空栈元素
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 :void
****************************************************/
void LinkStack_Clear(LinkStack* stack);
/****************************************************
入栈
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
void* item -- 元素指针
返回值 : TRUE (1) || FALSE (0)
****************************************************/
int LinkStack_Push(LinkStack* stack, void* item);
/****************************************************
出栈
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 : void* (泛型元素指针)|| NULL (空)
****************************************************/
void* LinkStack_Pop(LinkStack* stack);
/****************************************************
获取栈顶元素
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 : void* (泛型元素指针)|| NULL (空)
****************************************************/
void* LinkStack_Top(LinkStack* stack);
/****************************************************
获取栈数据长度
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 : 栈元素个数 (int)
****************************************************/
int LinkStack_Size(LinkStack* stack);
#pragma endregion
#endif //_LINK_STACK_H_
链栈操作函数实现源文件
#include
#include
#include
#include "LinkStack.h"
#include "LinkList.h" //单链表头文件
/*链栈内部数据结构*/
typedef struct _tag_LinkStackNode
{
TLKTNode node; //占位结构。。。只要定义一个和node节大小一样的数据即可 (单链表元素节点)
void *item;
}TLSNode;
#pragma region 链栈的基本函数实现
/****************************************************
创建一个空的链式栈
--------------------------------------------------
参数 :void
返回值 :LinkStack* | NULL
****************************************************/
LinkStack* LinkStack_Create()
{
/*创建链栈,相当于创建一个单链表,由于类型都是 void* 无需转换,直接返回即可*/
return LinkList_Create();
}
/****************************************************
释放栈空间
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 :void
****************************************************/
void LinkStack_Destroy(LinkStack* stack)
{
/*注意:释放栈空间的时候要把栈中所有元素清空 ,销毁栈等同于销毁线性表*/
LinkStack_Clear(stack);
LinkList_Destroy(stack);
return;
}
/****************************************************
清空栈元素
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 :void
****************************************************/
void LinkStack_Clear(LinkStack* stack)
{
if (stack == NULL)
{
return;
}
while (LinkStack_Size(stack) > 0)
{
/*栈中元素的声明周期,在入栈时开辟空间 ,在出栈时释放空间*/
LinkStack_Top(stack);//出栈函数中释放内存
}
return;
}
/****************************************************
入栈
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
void* item -- 元素指针
返回值 : TRUE (1) || FALSE (0)
****************************************************/
int LinkStack_Push(LinkStack* stack, void* item)
{
/*入栈,相当于向单链表中插入元素*/
int ret = 0;
TLSNode* tmp = (TLSNode*)malloc(sizeof(TLSNode));
if (tmp==NULL)
{
return -1;
}
memset(tmp, 0x00, sizeof(TLSNode));
tmp->item = item;
//入栈,等同于但单链表头插法,但在插入元素时,需要将 链栈元素节点类型 转换为 单链表元素节点类型
ret = LinkList_Insert(stack, (TLKTNode*)(&tmp->node), 0);
if (ret != 1)
{
free(tmp);
}
return ret;
}
/****************************************************
出栈
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 : void* (泛型元素指针)|| NULL (空)
****************************************************/
void* LinkStack_Pop(LinkStack* stack)
{
void *itemTmp = NULL;
TLSNode *ptrTmp = NULL;
ptrTmp = (TLSNode *)LinkList_Delete(stack, 0); //调用单链表操作函数
if (ptrTmp==NULL)
{
return NULL;
}
itemTmp = ptrTmp->item; //将单链表节点 转化为 链栈的业务节点
if (ptrTmp!=NULL)//在入栈的时候分配了内存,出栈时必须释放
{
free(ptrTmp);
}
return itemTmp;
}
/****************************************************
获取栈顶元素
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 : void* (泛型元素指针)|| NULL (空)
****************************************************/
void* LinkStack_Top(LinkStack* stack)
{
void *itemTmp = NULL;
TLSNode *ptrTmp = NULL;
ptrTmp = (TLSNode *)LinkList_Get(stack, 0); //调用单链表操作函数
if (ptrTmp==NULL)
{
return NULL;
}
itemTmp = ptrTmp->item;
return itemTmp;
}
/****************************************************
获取栈数据长度
----------------------------------------------------
参数 :LinkStack* stack -- 栈指针
返回值 : 栈元素个数 (int)
****************************************************/
int LinkStack_Size(LinkStack* stack)
{
return LinkList_Length(stack);
}
#pragma endregion
内嵌单链表,详情参阅前面博客:数据结构:线性表链式存储结构(单链表) C语言版
使用演示:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include "LinkStack.h"
typedef struct _User_info
{
int age;
char name[16];
}User;
int main(void)
{
User users[10];
LinkStack * stack = NULL;
char str[10] = {
0 };
char s1[10] = "name";
for (int i = 0; i < 10; i++)
{
users[i].age = 10 + i;
memset(str, 0x00, 10);
_itoa(10 + i, str, 10);
strcat(str, s1);
memset(users[i].name, 0x00, sizeof(users[i].name));
memcpy(users[i].name, str, strlen(str));
}
stack = LinkStack_Create();//创建链表
for (int i = 0; i < 10;i++)
{
LinkStack_Push(stack, &users[i]);//入栈
}
//获取栈中元素个数
int num = LinkStack_Size(stack);
printf("栈元素个数= %d \n", num);
//获取栈顶元素
User *tmp = (User *)LinkStack_Top(stack);
if (tmp==NULL)
{
printf("获取元素失败! \n");
}
else
{
printf("栈顶元素 age=%d ; name= %s \n", tmp->age, tmp->name);
}
while (LinkStack_Size (stack)>0)
{
User* tmp = (User *)LinkStack_Pop(stack);
if (tmp == NULL)
{
printf("获取元素失败! \n");
}
else
{
printf("栈顶元素 age=%d ; name= %s \n", tmp->age, tmp->name);
}
}
//获取栈中元素个数
num = LinkStack_Size(stack);
printf("出栈后元素个数= %d \n", num);
//释放栈空间
LinkStack_Destroy(stack);
system("pause");
return 0;
}