数据结构:栈(Stack 链式存储结构) C语言版

链式存储结构栈

栈的链式存储结构,简称链栈。
栈只能从栈顶来作插入和删除动作,由于链表有头指针,而栈顶指针也是必须的,所以比较好的方法是把栈顶放在链表的头部。另外,都已经有了栈顶在链表头部了,单链表中比较常用的头节点也就失去了意义,通常对于链栈来说,是不需要头结点的。
链式栈模型
对于链栈来说,基本不会存在栈满的情况,除非内存已经没有可用的使用空间,如果发生则计算机系统将死机崩溃,而不是链栈是否溢出的问题。
对于空栈来说,链表原定义的头指针指向空,那么链栈的空其实就是 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 <stdlib.h>
#include <string.h>
#include <memory.h>

#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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#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;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值