链式存储-循环链表


循环链表

在单链表中,存在这样一个问题,如果不从头结点出发,就无法访问到全部结点。

而为了解决这个问题,只需要将单链表终端结点的指针域由空指针改为指向头结点。这种方法类似于静链表中,最后一个元素的游标存放第一个有数值的元素的下标,这两者有异曲同工之妙。

将单链表终端结点的指针域端由空指针改为指向头结点,就使单链表形成了一个环,这种头尾相接的链表叫做单循环链表,简称循环链表。

一、循环链表的创建(结合图片一起看)

此处及以下使用了知识点(指针的指针),不明白的朋友可以了解
指针作为函数参数传递以及指针的指针

#include <stdio.h>
#include <stdlib.h>

typedef struct List
{
	int data;
	struct List* next;
}list,*p_list;

//创建循环链表
void creat_list(list** p)	//带**的为指向指针的指针(双重指针),因此**p为头指针(指向头结点的指针),*p为头结点
							//如果链表为空,则创建一个链表,指针域指向自己,否则寻找尾结点
{							//将尾结点的指针指向这个新结点,新结点的指针域指向头结点
	int item;	//数据存储变量
	list* temp;	//作为新结点
	list* target;	//作为尾结点
	printf("输入结点的值,输入0结束\n");
	while (1)
	{
		scanf("%d", &item);
		if (item == 0)return;

		if (*p == NULL)	//如果输入的链表为空,则创建一个新的结点,使其next指向自己	(*head)->next=head;
		{
			*p = (list*)malloc(sizeof(list));
			if (!*p)exit(0);
			(*p)->data = item;
			(*p)->next = *p;
		}

		else
		{//输入的链表不为空,寻找链表的尾结点,使尾结点的next=新节点,新节点的next指向头结点
			for (target = *p; target->next != *p; target = target->next);//此时target为尾结点

			temp = (list*)malloc(sizeof(list));//创建新结点
			if (!item)exit(0);
			temp->data = item;	//数据存入新结点数据域
			temp->next = *p;	//新结点指向头结点
			target->next = temp;	//将尾结点与新结点链接
		}
	}
}

单循环链表示意图

二、循环链表的遍历

//循环链表的遍历
void show(list* p)	//*p为头结点,传入的是头结点
{
	list* temp;
	temp = p;
	do
	{
		printf("%5d", temp->data);
		temp = temp->next;
	} while (temp != p);	//当前结点不为头结点
	
	printf("\n");
}

三、循环链表的插入

//循环链表的插入
void insert(list** pNode, int place, int num)	//传入的是头指针
{
	list* temp, * target;
	int i;
	if (place == 1)
	{
		temp = (list*)malloc(sizeof(list));	//创建新结点
		if (!temp)exit(0);
		temp->data = num;
		for (target = *pNode; target->next != *pNode; target = target->next);	//寻找尾结点

		temp->next = *pNode;	//新结点指向头结点
		target->next = temp;	//尾结点指向新结点
		*pNode = temp;	//注意:改变主函数中的头结点,新结点作为新的头结点
	}
	else
	{
		for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next);	//寻找插入位置
		temp = (list*)malloc(sizeof(list));	//创建新结点
		temp->data = num;

		temp->next = target->next;	//插入结点指向插入位置后的结点
		target->next = temp;	//插入位置前的结点指向插入结点
	}
}

四、循环链表的删除

//循环链表的删除
void delete(list**pNode,int place)	//传入的是头指针
{
	list* temp, * target;
	int i;
	temp = *pNode;
	if(temp == NULL)	//首先判断链表是否为空
	{
		printf("这是一个空指针,无法删除\n");
		return;
	}

	if (place == 1)	//如果删除的是头结点	
	{				//特殊处理,先找到尾结点,更新头结点为原头结点的下一结点,使尾结点的next指向新头结点,释放原头结点
		for (target = *pNode; target->next != *pNode; target = target->next);	//寻找尾结点
		temp = *pNode;

		*pNode = (*pNode)->next;	//更新头结点为原头结点的下一结点
		target->next = *pNode;	//尾结点指向新头结点
		free(temp);	//释放原头结点
	}

	else//删除其他结点
	{	//寻找删除结点的前一个结点
		for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next, i++);

		if (target->next == *pNode)	//如果删除结点为尾结点
		{
			for (target = *pNode; target->next->next != *pNode; target = target->next);//寻找尾结点的前一个结点
			temp = target->next;	//temp为尾结点
			target->next = *pNode;	//删除结点的前一个结点指向头结点
			free(temp);	//释放尾结点
		}
		else//删除其他情况的结点时
		{	//此时target为删除结点的前一个结点
			temp = target->next;	//temp为删除结点
			target->next = temp->next;	//删除结点的前一个结点与删除结点的后一个结点链接
			free(temp);	//释放删除结点
		}
	}

	//总结:
	//target为删除结点的前一个节点为
	//temp始终为删除结点
	//先将删除结点的前一个节点与删除结点的后一个结点链接,即target->next=temp->next;
	//再释放删除结点	free(temp);
}

五、查找值

//查找值
int findval(list* pNode, int val)	//传入的是头结点
									//寻找值,返回位置
{
	int i = 1;	//从1开始,因为头结点也有值
	list* node;
	node = pNode;

	while (node->data != val && node->next != pNode)
	{
		i++;
		node = node->next;
	}
	if (node->next == pNode && node->data != val)	//检索到尾结点时跳出,因此还要检测目标是否为尾结点的data
	{
		return -1;
	}
	return i;
}

完整代码

#include <stdio.h>
#include <stdlib.h>

typedef struct List
{
	int data;
	struct List* next;
}list,*p_list;

//创建循环链表
void creat_list(list** p)	//带**的为指向指针的指针(双重指针),因此**p为头指针(指向头结点的指针),*p为头结点
							//如果链表为空,则创建一个链表,指针域指向自己,否则寻找尾结点
{							//将尾结点的指针指向这个新结点,新结点的指针域指向头结点
	int item;	//数据存储变量
	list* temp;	//作为新结点
	list* target;	//作为尾结点
	printf("输入结点的值,输入0结束\n");
	while (1)
	{
		scanf("%d", &item);
		if (item == 0)return;

		if (*p == NULL)	//如果输入的链表为空,则创建一个新的结点,使其next指向自己	(*head)->next=head;
		{
			*p = (list*)malloc(sizeof(list));
			if (!*p)exit(0);
			(*p)->data = item;
			(*p)->next = *p;
		}

		else
		{//输入的链表不为空,寻找链表的尾结点,使尾结点的next=新节点,新节点的next指向头结点
			for (target = *p; target->next != *p; target = target->next);//此时target为尾结点

			temp = (list*)malloc(sizeof(list));//创建新结点
			if (!item)exit(0);
			temp->data = item;	//数据存入新结点数据域
			temp->next = *p;	//新结点指向头结点
			target->next = temp;	//将尾结点与新结点链接
		}
	}
}

//循环链表的遍历
void show(list* p)	//*p为头结点,传入的是头结点
{
	list* temp;
	temp = p;
	do
	{
		printf("%5d", temp->data);
		temp = temp->next;
	} while (temp != p);	//当前结点不为头结点
	
	printf("\n");
}

//循环链表的插入
void insert(list** pNode, int place, int num)	//传入的是头指针
{
	list* temp, * target;
	int i;
	if (place == 1)
	{
		temp = (list*)malloc(sizeof(list));	//创建新结点
		if (!temp)exit(0);
		temp->data = num;
		for (target = *pNode; target->next != *pNode; target = target->next);	//寻找尾结点

		temp->next = *pNode;	//新结点指向头结点
		target->next = temp;	//尾结点指向新结点
		*pNode = temp;	//注意:改变主函数中的头结点,新结点作为新的头结点
	}
	else
	{
		for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next);	//寻找插入位置
		temp = (list*)malloc(sizeof(list));	//创建新结点
		temp->data = num;

		temp->next = target->next;	//插入结点指向插入位置后的结点
		target->next = temp;	//插入位置前的结点指向插入结点
	}
}

//循环链表的删除
void delete(list**pNode,int place)	//传入的是头指针
{
	list* temp, * target;
	int i;
	temp = *pNode;
	if(temp == NULL)	//首先判断链表是否为空
	{
		printf("这是一个空指针,无法删除\n");
		return;
	}

	if (place == 1)	//如果删除的是头结点	
	{				//特殊处理,先找到尾结点,更新头结点为原头结点的下一结点,使尾结点的next指向新头结点,释放原头结点
		for (target = *pNode; target->next != *pNode; target = target->next);	//寻找尾结点
		temp = *pNode;

		*pNode = (*pNode)->next;	//更新头结点为原头结点的下一结点
		target->next = *pNode;	//尾结点指向新头结点
		free(temp);	//释放原头结点
	}

	else//删除其他结点
	{	//寻找删除结点的前一个结点
		for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next, i++);

		if (target->next == *pNode)	//如果删除结点为尾结点
		{
			for (target = *pNode; target->next->next != *pNode; target = target->next);//寻找尾结点的前一个结点
			temp = target->next;	//temp为尾结点
			target->next = *pNode;	//删除结点的前一个结点指向头结点
			free(temp);	//释放尾结点
		}
		else//删除其他情况的结点时
		{	//此时target为删除结点的前一个结点
			temp = target->next;	//temp为删除结点
			target->next = temp->next;	//删除结点的前一个结点与删除结点的后一个结点链接
			free(temp);	//释放删除结点
		}
	}

	//总结:
	//target为删除结点的前一个节点为
	//temp始终为删除结点
	//先将删除结点的前一个节点与删除结点的后一个结点链接,即target->next=temp->next;
	//再释放删除结点	free(temp);
}

//查找值
int findval(list* pNode, int val)	//传入的是头结点
									//寻找值,返回位置
{
	int i = 1;	//从1开始,因为头结点也有值
	list* node;
	node = pNode;

	while (node->data != val && node->next != pNode)
	{
		i++;
		node = node->next;
	}
	if (node->next == pNode && node->data != val)	//检索到尾结点时跳出,因此还要检测目标是否为尾结点的data
	{
		return -1;
	}
	return i;
}
int main()
{
	list* head = NULL;
	list* val = NULL;
	int place, num;
	creat_list(&head);
	printf("原始的链表:");
	show(head);

	printf("请输入要删除的位置:");
	scanf("%d", &place);
	delete(&head, place);
	show(head);

	printf("请输入插入的位置和数据,用空格隔开:");
	scanf("%d%d", &place, &num);
	insert(&head, place, num);
	show(head);

	printf("请输入你想要查找的值:");
	scanf("%d", &num);
	place = findval(head, num);
	if (place != -1)printf("找到的值的位置是place=%d\n", place);
	else
		printf("没有找到该值\n");

	return 0;
}

转载于:https://www.cnblogs.com/dakewei/p/11378713.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值