C语言中链表的相交,和环形链表

C语言中链表的相交,和环形链表

1.链表的相交

相交链表的特性就是它们走到最后都会指向同一个尾节点。
请添加图片描述
两个链表都是未知的又如何找到它们的交点呢?只需要让节点长的先走它们的差步,再同时走,第一次相遇的节点就是它们的相交点。
第一步:判断是否相交(不相交直接结束)
以下都是建立在相交情况下
第二部:计算链表1和链表2的节点数之差(n)
第三步:让链表长的先走n步
第四步:再同时走,第一次相遇的节点就为交点
实现代码如下:

#include<stdio.h>
typedef struct SList
{
	int num;
	struct SList* next;
}SL;

//寻找相交点 
void FoundIntersect(SL* phead1,SL* phead2,int SListsize1,int SListsize2)
{
	//先计算出两个链表的节点数之差 
	int temp=abs(SListsize1-SListsize2);
	//让节点数多的先走temp步 
	if(SListsize1<SListsize2)
		while(temp--)
			phead2=phead2->next;
	else
		while(temp--)
			phead1=phead1->next;
	//同时走,第一次相同时的节点即为相交点 
	while(phead1&&phead2)
	{
		if(phead1==phead2)
			break;
		phead1=phead1->next;
		phead2=phead2->next;	
	}
	printf("节点地址为:%p   节点值为:%d\n",phead1,*phead1);
}

//判断是否相交 ,并顺便计算两个链表的长度,相交返回1,不相交返回0 
int Intersect(SL* phead1,SL* phead2,int* SListsize1,int* SListsize2)
{
	while(phead1)
	{
		phead1=phead1->next;
		(*SListsize1)++;
	}
	while(phead2)
	{
		phead2=phead2->next;
		(*SListsize2)++;
	}
	if(phead1==phead2)
	{
		printf("相交\n");
		return 1;
	}
	else
	{
		printf("不相交\n");
		return 0;
	}
}

int main()
{
	//定义两个变量存储,falg用来判断是否找相交点
	int SListsize1=0,SListsize2=0,flag;
	
	//暴力创建两个链表 
	SL node1,node2,node3,node4,node5,node6,node7,node8;
	node7.num=5,node7.next=&node8;
	node8.num=4,node8.next=NULL;
	
	//链表1    
	node1.num=3,node1.next=&node2;
	node2.num=1,node2.next=&node3;
	node3.num=7,node3.next=&node4;
	node4.num=1,node4.next=&node7;

	//链表2   
	node5.num=4,node5.next=&node6;
	node6.num=6,node6.next=&node7;
	
	SL* phead1=&node1;
	SL* phead2=&node5;
	//判读是否相交 ,并顺便计算两个链表的长度
	flag=Intersect(phead1,phead2,&SListsize1,&SListsize2);
	//如果相交找到相交点 
	if(flag)
		FoundIntersect(phead1,phead2,SListsize1,SListsize2);
}

运行程序如下:
在这里插入图片描述

2.环形链表

即是一个链表的尾节点的指针指向了链表中的某一个节点,造成了链表的死循环
如何判断一个链表是否为环形链表?
思路:定义两个指针fast和slow,fast一直走两步,slow一次走一步,当他们进入循环之后一定会相遇,即这个链表为环形链表,如果fast走到NULL说明不是环形链表。请添加图片描述
拓展问题:
如果fast走三步,四步,五部等等,slow走两步,三步,四步等等它们还会在环中相遇吗?(fast>slow)
在这里插入图片描述

设它们都入环后的距离为x,环大小为y,slow走一步,fast走三步
第一次 x
第二次 x-2
第三次 x-4
第四次 x-6

第n次 0或-1
当x为2的倍数时,n为0,为0就意味着它们相遇
当x不为2的倍数时,n为-1,为-1时就意味着fast又超过slow一步,此时y-1如果不能被2(这里的2是slow和fast的差)除尽,那么它们将永远都不会相遇了。

又例如:
slow走一步,fast走四步
第一次 x
第二次 x-3
第三次 x-6
第四次 x-9

第n次 0或-1或-2
当x为3的倍数时,n为0,为0就意味着它们相遇
当x不为3的倍数时,n为-1或-2,为-1时就意味着fast又超过slow一步,此时y-1如果不能被3(这里的3是slow和fast的差)除尽,那么它们将永远都不会相遇了。同理,-2就意味着fast又超过slow两步,如果y-2不能被3除尽那么它们也不会再相遇了。

找相交点:
方法一:
在它们相遇后将相遇节点的next置为空此时就变成了两个相交的链表,找到相交点即为环形链表入口点,照相点的方法可以参考第一列。这里不演示这种方法的代码。
在这里插入图片描述

方法二:
根据推导公式求相遇点
在这里插入图片描述
实现代码如下:

#include<stdio.h>
typedef struct SList
{
	int num;
	struct SList* next;
}SL;

//判断接收的结构体指针是否为环形链表
void SLAnnular(SL* phead)
{
	SL* fast=phead,*slow=phead;
	SL* meetnode;
	
	//先找到相遇点
	while(fast)
	{
		fast=fast->next->next;
		slow=slow->next;
		if(fast==slow)
			break;
	}
	if(fast==slow)
	{
		printf("是环形链表\n");
		meetnode=slow;
		
		//根据推导式找到入口点
		while(phead!=meetnode)
		{
			phead=phead->next;
			meetnode=meetnode->next;
		}
		printf("入口地址:%p  值:%d\n",meetnode,meetnode->num);
	}
	else
	{
		printf("不是环形链表\n");
	}
}

int main()
{
	//暴力创建链表 
	SL node1,node2,node3,node4,node5,node6;
	node1.num=3,node1.next=&node2;
	node2.num=9,node2.next=&node3;
	node3.num=8,node3.next=&node4;
	node4.num=1,node4.next=&node5;
	node5.num=4,node5.next=&node6;
	node6.num=6,node6.next=&node4;
	SL* phead=&node1;
	SLAnnular(phead);
}

运行代码如下:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值