线性表之循环链表(数据结构笔记)

循环链表是一种单链表的变体,其终端结点的指针指向头结点形成一个环。循环链表可能不包含头结点,并涉及特定的操作如首元素的插入和删除,以及链表的清空和遍历。实现循环链表时,通常会通过模板定义并继承自基础链表结构。
摘要由CSDN通过智能技术生成

线性表(List)

循环链表

将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表成为单循环链表,简称循环链表。
在这里插入图片描述

注: 循环链表不一点要有头结点。

循环链表的设计实现要点:

  • 通过模板定义CircleList,继承自LinkedList。
  • 定义连接链表首尾的内部函数。
  • 实现首元素的插入和删除操作。
  • 重写清空操作和遍历操作。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define ERROR 0
#define OK 1
typedef int EleType;
/*
循环链表的结构和单链表结构一样,不过对于单链表,每个结点只存储了向后的指针,
到了尾标志就停止了向后链的操作,这样知道某个结点却无法找到它的前驱结点。
将单链表中的终端点的指针由空指针改为指向头结点,就使整个单链表形成一个环,
这种头尾相接的单链表称为循环单链表,简称循环链表。
*/
typedef struct CLinkNode
{
	EleType data;
	struct CLinkNode *next;
}CLinkNode,*CLinkList;
 
/*
初始化循环链表
*/
int InitCLinkList(CLinkList *list)
{
	if (list == NULL)
	{
		return ERROR;
	}
 
	int data = 0;
	CLinkNode* target = NULL;
	CLinkNode* head_node = NULL;
	printf("请输入结点数据,0代表结束初始化:\n");
	//这里采用用户控制台输入数据,你也可以随机生成数据进行初始化
	while (1)
	{
		scanf("%d", &data);
		//fflush(stdin);
		if (data == 0)
		{
			//退出循环标志,用户输入0 表示结束输入数据
			break;
		}
 
		/*
		判断初始化的链表有没有结点
		没有结点 先创建头结点 然后插入数据
		有结点 将结点用尾插法插入到链表中
		最后 尾结点的 指针域 指向头结点 这样形成一个环
		*/
		if (*list == NULL)
		{
			CLinkNode* head= (CLinkNode*)malloc(sizeof(CLinkNode));
			//分配结点空间失败
			if (head == NULL)
			{
				exit(0);
			}
 
			*list = head;//链表指向头结点
 
			CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));
			if (node == NULL)
			{
				exit(0);
			}
			node->data = data;
			node->next = head;
			head->next = node;
		}
		else
		{
			//如果循环链表不为空 链尾部插入数据
			//通过循环 找到尾结点,怎样判断是否是尾结点?当结点的指针域指向头结点时为尾结点,这样才能形成环嘛
			//循环结束后target 指向尾结点
			//for 循环下好好理解下!target初始化为第一个结点指针
			for (target = (*list)->next; target->next != *list; target = target->next);
			head_node = target->next;
 
			CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));
			if (node == NULL)
			{
				exit(0);
			}
			node->data = data;
			node->next = head_node;
 
			target->next = node;//将新结点插入尾部
		}
 
	}
	return OK;
}
/*
往链表指定位置插入数据
list 循环链表
loc 第loc位置插入元素,loc 从1 开始计数
data 插入元素的数据域
*/
int InsertCLinkNode(CLinkList list,int loc, EleType data)
{
	if (list == NULL || loc < 1)
		return ERROR;
	/*
	循环目的:找到第loc-1位置结点
	*/
	int i = 1;// 按人类的读法 i表示第i个位置 和 loc 表达意思一致
	CLinkNode* node = list;//刚开始node指向头结点
	while (node->next!=list && i < loc)
	{
		node = node->next;
		i++;
	}
	/*
	这里while循环比较难理解,我们拿 3个元素循环链表 来讲解
	loc = 1 时 往第1个位置插入元素
	不进入循环 node 指向头结点 i == loc == 1 插入合法
	loc = 2 时
	node 指向 第1个结点,i = 2 跳出循环
	
	loc = 3 时
	node 指向 第1个结点,i = 2 循环继续
	node 指向 第2个结点,i = 3 跳出循环
	loc = 4 时 注意:如果有3个元素 往第4位置插入元素 是合法!等于往链表尾部插入元素。 
	node 指向 第1个结点,i = 2 循环继续
	node 指向 第2个结点,i = 3 循环继续
	node 指向 第3个结点,i = 4 跳出继续
	
	循环结束时 i==loc 才合法! 此时node 指向 第 loc-1 位置的结点
	将 新结点的指针域 指向 第loc-1位置的后继结点
	将 第loc-1位置的指针域 指向 新结点,这样新结点就插入到 循环链表的 第loc位置了!
	*/
 
	/*
	循环结束时 i==loc 才合法! 此时node 指向 第 loc-1 位置的结点
	将 新结点的指针域 指向 第loc-1位置的后继结点
	将 第loc-1位置的指针域 指向 新结点,这样新结点就插入到 循环链表的 第loc位置了!
	*/
	if (i == loc)
	{
		CLinkNode* new_node = (CLinkNode*)malloc(sizeof(CLinkNode));
		if (new_node == NULL)
		{
			exit(0);
		}
		new_node->data = data;
		new_node->next = node->next;//新结点指针域 指向前驱结点的后继结点
		node->next = new_node;//将新结点加入链表
	}
	else
	{
		return	ERROR;
	}
 
	return OK;
}
/*
删除指定结点,通过指针返回删除结点的数据
*/
int DelCLinkNode(CLinkList list,int loc, EleType* data)
{
	if (list == NULL || loc < 1)
		return ERROR;
	/*
	循环目的:找到第loc-1位置结点
	*/
	int i = 1;// 按人类的读法 i表示第i个位置 和 loc 表达意思一致
	CLinkNode* node = list;//刚开始node指向头结点
	while (node->next != list && i < loc)
	{
		node = node->next;
		i++;
	}
	//循环结束 node 指向 loc-1 位置 且 node 不能为尾结点,为什么不能为尾结点?因为不能删除 位置上没有元素的结点!
	if (i == loc && node->next != list)
	{
		CLinkNode* del_node = node->next;//第loc 位置结点
		*data = del_node->data;//返回删除结点的数据域
 
		node->next = del_node->next;// 删除结点的 前驱结点 指向删除结点的 后继结点,这样删除位置的结点就不在链表中了
		free(del_node);//释放空间
 
	}
	return OK;
}
/*
展示循环链表元素
*/
int ShowCLinkList(CLinkList list)
{
	if (list == NULL)
	{
		return ERROR;
	}
	CLinkNode* target = NULL;
	printf("--------循环链表元素------\n");
	for (target = list->next; target != list; target = target->next)
		printf("%d \t",target->data);
	printf("\n");
	return OK;
}
/*
获取链表元素个数
*/
int LengthCLinkList(CLinkList list)
{
	if (list == NULL)
	{
		return ERROR;
	}
	CLinkNode* target = NULL;
	int length = 0;
	for (target = list->next; target != list; target = target->next)
		length++;
	printf("循环链表元素个数:%d\n", length);
	return OK;
}
/*
获取根据数据获取结点的位置
*/
int IndexCLinkList(CLinkList list,int data)
{
	if (list == NULL)
	{
		return ERROR;
	}
	CLinkNode* target = NULL;
	int length = 0;
	int index = -1;
	for (target = list->next; target != list; target = target->next)
	{
		length++;
		if (target->data == data)
		{
			index = length;
		}
	}
	if (index == -1)
	{
		printf("数据%d在循环链表中不存在\n", data);
	}
	else
	{
		printf("数据%d在第%d个位置\n", data, index);
 
	}
	return index;
}
/*
获取第i个结点的数据内容
*/
int IndexOfCLinkList(CLinkList list, int index)
{
	if (list == NULL || index < 1)
	{
		return ERROR;
	}
	CLinkNode* target = NULL;
	int length = 0;
	int data = -1;
	for (target = list->next; target != list; target = target->next)
	{
		length++;
		if (length == index)
		{
			data = target->data;
		}
	}
	if (index > length)
	{
		printf("第%d个位置结点不存在\n", index);
	}
	else
	{
		printf("第%d个位置的数据:%d\n", index,data);
	}
	return data;
}
int main(int argc, char *argv[])
{
	int flag = 0;
	CLinkList list = NULL;
	while (1)
	{
		printf("===============循环链表功能菜单===========\n");
		printf("===============1、初始化循环链表==========\n");
		printf("===============2、插入元素================\n");
		printf("===============3、删除元素================\n");
		printf("===============4、展示元素================\n");
		printf("===============5、循环链表元素个数========\n");
		printf("===============6、根据数据查询结点位置====\n");
		printf("===============7、根据位置查询结点数据====\n");
		printf("===============0、退出菜单================\n");
		scanf("%d", &flag);
		//fflush(stdin);
		if (flag == 0)
			break;
		if (flag == 1)
		{
			list = NULL;
			InitCLinkList(&list);
			ShowCLinkList(list);
		}
		else if(flag == 2)
		{
			int loc = 0;
			int data = 0;
			printf("请输入插入元素的位置和数据:\n");
			scanf("%d", &loc);
			scanf("%d", &data);
			InsertCLinkNode(list, loc, data);
			ShowCLinkList(list);
		}
		else if (flag == 3)
		{
			int loc = 0;
			int data = 0;
			printf("请输入删除元素的位置:\n");
			scanf("%d", &loc);
			DelCLinkNode(list, loc, &data);
			ShowCLinkList(list);
		}
		else if (flag == 4)
		{
			ShowCLinkList(list);
		}
		else if (flag == 5)
		{
			LengthCLinkList(list);
		}
		else if (flag == 6)
		{
			int loc = 0;
			printf("请输入查找元素的位置:\n");
			scanf("%d", &loc);
			IndexOfCLinkList(list,loc);
		}
		else if (flag == 7)
		{
			int data = 0;
			printf("请输入查找元素的数据:\n");
			scanf("%d", &data);
			IndexCLinkList(list, data);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值