C语言数据结构———单项循环链表

单项循环链表

将单项非循环链表尾结点的指针域指向头结点即为单项循环链表。

一、单项循环链表结点数据类型

//数据节点 
typedef struct Node
{
	int dat;//结点值
	struct Node *pNext;//下一个结点
}Node, *pNode;
//Node   等效于 struct Node
//*pNode 等效于 struct Node *

二、创建单项循环链表

1.为单项循环链表头结点申请内存。

2.将头结点指针域指向头结点本身,即创建成功单项循环链表。

3.头结点数据域为零,表示单项循环链表有效节点个数。

注意:单项循环链表头结点存在的目的是方便操作链表,亦可不使用头结点。

如下图所示:
创建单项循环链表

//创建单项循环链表
Node * pCreat_sCircleLink(void)
{
	Node * pHeadNode = NULL;//头结点指针

	pHeadNode = (Node *)malloc(sizeof(Node));//为头结点申请内存
	if (pHeadNode == NULL)
	{
		printf("头结点申请内存失败,程序终止......\r\n");
		while (1);
	}

	pHeadNode->pNext = pHeadNode;//指向自身
	pHeadNode->dat   = 0;//节点数为0

	printf("创建单项循环链表成功......");
	printf("头结点:0x%08X    指针域:0x%08X    节点数:%d\r\n", pHeadNode, pHeadNode->pNext, pHeadNode->dat);

	return pHeadNode;
}

三、判断单项循环链表是否为空’

当单项循环链表头结点的数据域为零,且指针域指向头结点本身,则表示链表为空。

如下图所示:
单项循环链表为空

//判断单项循环链表是否为空
bool IsEmpty_sCircleLink(Node * pHeadLink)
{
	//节点数为零且指针域为自身
	if ((!pHeadLink->dat) && (pHeadLink->pNext == pHeadLink))
		return true;
	else
		return false;
}

四、寻找单项循环链表尾结点

结点指针域指向头结点的结点为尾结点。

1.获取头结点指针。

2.其指针域不等于链表头结点继续寻找。

3.移动指针,指向下一个结点。

//寻找单项循环链表尾结点
Node * SearchRearNode_sCircleLink(Node * pHeadLink)
{
	Node * pNode = NULL;//尾结点指针

	pNode = pHeadLink;//头结点指针
	while (pNode->pNext != pHeadLink)
		pNode = pNode->pNext;//下个结点

	return pNode;
}

五、向单项循环链表追加数据

在单项循环链表尾结点后添加新的结点。

1.获取链表尾结点指针。

2.为新加入的结点申请内存。

3.尾结点指针域指向新加入的结点。

4.新加入的结点指针域指向头结点。

5.新结点数据为追加的数据值。

如下图所示:
向单项循环链表追加数据

//向单项循环链表追加数据
void Append_sCircleLink(Node * pHeadLink, int value)
{
	Node * pRearNode = NULL;//尾结点指针
	Node * pNewNode  = NULL;//新结点指针

	pNewNode = (Node *)malloc(sizeof(Node));//为新结点申请内存
	if (pNewNode == NULL)
	{
		printf("新结点内存失败......\r\n");
		return;
	}

	pRearNode = SearchRearNode_sCircleLink(pHeadLink);//寻找单项循环链表尾结点
	if (pRearNode == NULL)
	{
		printf("无效尾结点......\r\n");
		return;
	}

	pRearNode->pNext = pNewNode;//尾结点指向新结点
	pNewNode->pNext  = pHeadLink;//新结点指向头结点,即为尾结点
	pNewNode->dat    = value;//追加值

	pHeadLink->dat++;//链表结点数量自加

	printf("追加数据成功......");
	printf("上结点:0x%08X\t本结点:0x%08X\t指针域:0x%08X\t节点数:%d\t追加值:%d\r\n", pRearNode, pNewNode, pNewNode->pNext, pHeadLink->dat, value);
}

六、向单项循环链表头结点追加数据

向单项循环链表头结点后添加新的结点。

1.为新加入的结点申请内存。

2.新结点指针域为头结点指针域。

3.头结点指针指向新加入的结点。

4.新结点数据域为追加的数据值。

如下图所示:
向单项循环链表头结点追加数据

//向单项循环链表头结点追加数据
void AppendHeadNode_sCircleLink(Node * pHeadLink, int value)
{
	Node * pNewNode = NULL;//新结点指针

	pNewNode = (Node *)malloc(sizeof(Node));//为新结点申请内存
	if (pNewNode == NULL)
	{
		printf("新结点内存失败......\r\n");
		return;
	}

	pNewNode->pNext  = pHeadLink->pNext;//新节点为第一个有效结点
	pHeadLink->pNext = pNewNode;//头结点指向新节点
	pNewNode->dat = value;//追加值

	pHeadLink->dat++;//链表结点数量自加

	printf("头结点追加数据成功......");
	printf("头指域:0x%08X\t本结点:0x%08X\t指针域:0x%08X\t节点数:%d\t追加值:%d\r\n", pHeadLink->pNext, pNewNode, pNewNode->pNext, pHeadLink->dat, value);
}

七、向单项循环链表某处插入数据

1.寻找插入位置之前的结点指针(尾结点指针)。

2.为新加入的结点申请内存。

3.新结点指针域指针尾结点指针域。

4.尾结点指针域指向新结点。

5.新节点数据域为插入的数据。

6.链表结点数加一。

注意:
1. 向单项循环链表某处插入新结点,头结点后为开始位置,默认为1。

如下图所示:
向单项循环链表某处插入数据

//向单项循环链表某处插入数据
void Insert_sCircleLink(Node * pHeadLink, int pos, int value)
{
	Node * pNewNode  = NULL;//新结点指针
	Node * pRearNode = NULL;//尾结点指针
	int i = 0;


	//判断插入位置的合法性
	if ((pHeadLink == NULL) || (pos < 1) || (pos > (pHeadLink->dat + 1)))
	{
		printf("插入位置无效......\r\n");
		return;
	}

	//寻找插入点之前的有效位置(尾结点)
	pRearNode = pHeadLink;//头结点指针
	while ((pRearNode->pNext != pHeadLink) && (i < (pos - 1)))
	{
		pRearNode = pRearNode->pNext;
		i++;
	}

	pNewNode = (Node *)malloc(sizeof(Node));//为新结点申请内存
	if (pNewNode == NULL)
	{
		printf("新结点内存失败......\r\n");
		return;
	}

	pNewNode->pNext  = pRearNode->pNext;//新节点指向尾结点后个结点
	pRearNode->pNext = pNewNode;//新结点插入尾结点之后
	pNewNode->dat    = value;//插入值

	pHeadLink->dat++;//链表结点数量自加

	printf("插入数据成功......");
	printf("上结点:0x%08X\t本结点:0x%08X\t指针域:0x%08X\t节点数:%d\t位置:%d\t  插入值:%d\r\n", pRearNode, pNewNode, pNewNode->pNext, pHeadLink->dat, pos, value);
}

八、删除单项循环链表某处结点

1.判断删除位置为有效位置。

2.寻找删除位置之前的结点,称为尾结点,删除尾结点之后的结点即可。

4.保存将要删除的结点指针。

5.尾结点指针指向下一个结点的下一个结点。

6.保存删除结点的数据。

7.释放删除结点内存。

8.链表结点数减一。

注意:
1. 删除单项循环链表某处结点,头结点后为开始位置,默认为1。

如下图所示:
在这里插入图片描述

//删除单项循环链表某处数据
int Delete_sCircleLink(Node * pHeadLink, int pos)
{
	Node * pRearNode = NULL;//尾结点指针
	Node * pNode = NULL;//结点指针
	int value = 0;
	int i = 0;


	//判断删除位置的合法性
	if ((pHeadLink == NULL) || (pos < 1) || (pos > pHeadLink->dat))
	{
		printf("删除位置无效......\r\n");
		return value;
	}


	//寻找删除点之前的有效位置(尾结点)
	pRearNode = pHeadLink;//头结点指针
	while ((pRearNode->pNext != pHeadLink) && (i < (pos - 1)))
	{
		pRearNode = pRearNode->pNext;
		i++;
	}

	pNode = pRearNode->pNext;//将删除的结点
	pRearNode->pNext = pNode->pNext;//指向将删除结点的下个结点
	value = pNode->dat;//将删除的结点值
	free(pNode);//释放删除结点内存

	pHeadLink->dat--;//链表结点数量自减

	printf("删除数据成功......");
	printf("上结点:0x%08X\t指针域:0x%08X\t本结点:0x%08X\t节点数:%d\t删除值:%d\r\n", pRearNode, pRearNode->pNext, pNode, pHeadLink->dat, value);

	return value;
}

九、删除单项循环链表尾部数据

1.链表非空时才可删除尾部结点。

2.获取第一个有效结点指针。

3.寻找尾结点之前的第一个有效结点,另称为尾结点。

4.保存要删除的结点指针。

5.尾结点指针指向下一个结点的指针域。

6.获取将要删除的结点数据。

7.释放将要删除的结点内存。

8 链表结点数减一。

如下图所示:
在这里插入图片描述

//删除单项循环链表尾部数据
int DeleteEnd_sCircleLink(Node * pHeadLink)
{
	Node * pRearNode = NULL;//尾结点指针
	Node * pNode = NULL;//结点指针
	int  value = 0;
	int  i = 0;


	if (IsEmpty_sCircleLink(pHeadLink))//判断单项循环链表是否为空
	{
		printf("空链表......\r\n");
		return  value;
	}


	//寻找删除点之前的有效位置(尾结点)
	pRearNode = pHeadLink;//头结点指针
	while ((pRearNode->pNext != pHeadLink) && (i < (pHeadLink->dat - 1)))
	{
		pRearNode = pRearNode->pNext;
		i++;
	}

	pNode = pRearNode->pNext;//将删除的结点
	pRearNode->pNext = pNode->pNext;//尾结点指向删除后的结点
	value = pNode->dat;//将删除的结点值
	free(pNode);//释放删除结点内存

	pHeadLink->dat--;//链表结点数量自减

	printf("删除数据成功......");
	printf("上结点:0x%08X\t指针域:0x%08X\t本结点:0x%08X\t节点数:%d\t删除值:%d\r\n", pRearNode, pRearNode->pNext, pNode, pHeadLink->dat, value);

	return  value;
}

十、清空单项循环链

1.获取第一个有效结点。

2.获取去有效结点指针域,即指向下下个结点。

3.释放结点内存。

4.链表结点数加一。

5.直到为头结点为此,或者链表为空为此。

如下图所示:
在这里插入图片描述

//清空单项循环链
void Clear_sCircleLink(Node * pHeadLink)
{
	Node * delNode = NULL;//删除结点指针
	int i = 0;

	for (i = 0; i < pHeadLink->dat; )
	{
		delNode = pHeadLink->pNext;//第一个有效结点
		pHeadLink->pNext = delNode->pNext;//头结点指针域指向下个有效结点
		pHeadLink->dat--;//结点数自减
		free(delNode);//释放结点内存
	}

	printf("清空链表成功......");
	printf("头结点:0x%08X\t指针域:0x%08X\t节点数:%d\r\n", pHeadLink, pHeadLink->pNext, pHeadLink->dat);
}

十一、显示单项循环链表结点数据

//显示单项循环链表结点数据
void Show_sCircleLink(Node * pHeadLink)
{
	Node * pNode = NULL;//结点指针

	if (IsEmpty_sCircleLink(pHeadLink) == true)
	{
		printf("单项循环链表为空......\r\n");
		return;
	}

	printf("循环链表结点数据:");
	pNode = pHeadLink->pNext;//第一个有效结点
	while(pNode != pHeadLink)//不为头结点
	{
		printf("%d  ", pNode->dat);//结点数据
		pNode = pNode->pNext;//下一个结点
	}
	printf("\r\n");
}

十二、获取单项循环链表的结点数

//获取单项循环链表的结点数
int GetCount_sCircleLink(Node * pHeadLink)
{
	return pHeadLink->dat;
}

十三、代码验证演示

void main(void)
{
	Node * pHeadLink = NULL;//头结点指针

	pHeadLink = pCreat_sCircleLink();//创建单项循环链表
	printf("\r\n");

	Append_sCircleLink(pHeadLink, 100);//向单项循环链表追加数据
	Append_sCircleLink(pHeadLink, 200);
	Append_sCircleLink(pHeadLink, 300);
	Append_sCircleLink(pHeadLink, 400);
	Append_sCircleLink(pHeadLink, 500);
	Append_sCircleLink(pHeadLink, 600);
	Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
	printf("\r\n");

	AppendHeadNode_sCircleLink(pHeadLink, 10);//向单项循环链表头结点追加数据
	AppendHeadNode_sCircleLink(pHeadLink, 20);
	AppendHeadNode_sCircleLink(pHeadLink, 30);
	AppendHeadNode_sCircleLink(pHeadLink, 40);
	AppendHeadNode_sCircleLink(pHeadLink, 50);
	AppendHeadNode_sCircleLink(pHeadLink, 60);
	Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
	printf("\r\n");

	Insert_sCircleLink(pHeadLink, 1, 11);//向单项循环链表某处插入数据
	Insert_sCircleLink(pHeadLink, 2, 22);
	Insert_sCircleLink(pHeadLink, 3, 33);
	Insert_sCircleLink(pHeadLink, 4, 44);
	Insert_sCircleLink(pHeadLink, 5, 55);
	Insert_sCircleLink(pHeadLink, 6, 66);
	Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
	printf("\r\n");

	Delete_sCircleLink(pHeadLink, 1);//删除单项循环链表某处数据
	Delete_sCircleLink(pHeadLink, 2);
	Delete_sCircleLink(pHeadLink, 3);
	Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
	printf("\r\n");

	DeleteEnd_sCircleLink(pHeadLink);//删除单项循环链表尾部数据
	DeleteEnd_sCircleLink(pHeadLink);
	DeleteEnd_sCircleLink(pHeadLink);
	Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
	printf("\r\n");

	Clear_sCircleLink(pHeadLink);//清空单项循环链
	Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
	printf("\r\n");
	while (1);
}

十四、运行结果

创建单项循环链表成功......头结点:0x01359248    指针域:0x01359248    节点数:0

追加数据成功......上结点:0x01359248     本结点:0x01359750       指针域:0x01359248       节点数:1        追加值:100
追加数据成功......上结点:0x01359750     本结点:0x01359798       指针域:0x01359248       节点数:2        追加值:200
追加数据成功......上结点:0x01359798     本结点:0x013597E0       指针域:0x01359248       节点数:3        追加值:300
追加数据成功......上结点:0x013597E0     本结点:0x01359828       指针域:0x01359248       节点数:4        追加值:400
追加数据成功......上结点:0x01359828     本结点:0x01359870       指针域:0x01359248       节点数:5        追加值:500
追加数据成功......上结点:0x01359870     本结点:0x013598B8       指针域:0x01359248       节点数:6        追加值:600
循环链表结点数据:100  200  300  400  500  600

头结点追加数据成功......头指域:0x01359900       本结点:0x01359900       指针域:0x01359750       节点数:7        追加值:10
头结点追加数据成功......头指域:0x01359948       本结点:0x01359948       指针域:0x01359900       节点数:8        追加值:20
头结点追加数据成功......头指域:0x01359990       本结点:0x01359990       指针域:0x01359948       节点数:9        追加值:30
头结点追加数据成功......头指域:0x013599D8       本结点:0x013599D8       指针域:0x01359990       节点数:10       追加值:40
头结点追加数据成功......头指域:0x01359A20       本结点:0x01359A20       指针域:0x013599D8       节点数:11       追加值:50
头结点追加数据成功......头指域:0x01359A68       本结点:0x01359A68       指针域:0x01359A20       节点数:12       追加值:60
循环链表结点数据:60  50  40  30  20  10  100  200  300  400  500  600

插入数据成功......上结点:0x01359248     本结点:0x01359AB0       指针域:0x01359A68       节点数:13       位置:1    插入值:11
插入数据成功......上结点:0x01359AB0     本结点:0x01359AF8       指针域:0x01359A68       节点数:14       位置:2    插入值:22
插入数据成功......上结点:0x01359AF8     本结点:0x01359B40       指针域:0x01359A68       节点数:15       位置:3    插入值:33
插入数据成功......上结点:0x01359B40     本结点:0x01359B88       指针域:0x01359A68       节点数:16       位置:4    插入值:44
插入数据成功......上结点:0x01359B88     本结点:0x01359BD0       指针域:0x01359A68       节点数:17       位置:5    插入值:55
插入数据成功......上结点:0x01359BD0     本结点:0x01359C18       指针域:0x01359A68       节点数:18       位置:6    插入值:66
循环链表结点数据:11  22  33  44  55  66  60  50  40  30  20  10  100  200  300  400  500  600

删除数据成功......上结点:0x01359248     指针域:0x01359AF8       本结点:0x01359AB0       节点数:17       删除值:11
删除数据成功......上结点:0x01359AF8     指针域:0x01359B88       本结点:0x01359B40       节点数:16       删除值:33
删除数据成功......上结点:0x01359B88     指针域:0x01359C18       本结点:0x01359BD0       节点数:15       删除值:55
循环链表结点数据:22  44  66  60  50  40  30  20  10  100  200  300  400  500  600

删除数据成功......上结点:0x01359870     指针域:0x01359248       本结点:0x013598B8       节点数:14       删除值:600
删除数据成功......上结点:0x01359828     指针域:0x01359248       本结点:0x01359870       节点数:13       删除值:500
删除数据成功......上结点:0x013597E0     指针域:0x01359248       本结点:0x01359828       节点数:12       删除值:400
循环链表结点数据:22  44  66  60  50  40  30  20  10  100  200  300

清空链表成功......头结点:0x01359248     指针域:0x01359248       节点数:0
单项循环链表为空......
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值