相交链表的特性就是它们走到最后都会指向同一个尾节点。
两个链表都是未知的又如何找到它们的交点呢?只需要让节点长的先走它们的差步,再同时走,第一次相遇的节点就是它们的相交点。
第一步:判断是否相交(不相交直接结束)
以下都是建立在相交情况下
第二部:计算链表1和链表2的节点数之差(n)
第三步:让链表长的先走n步
第四步:再同时走,第一次相遇的节点就为交点
实现代码如下:
#include
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);
}
运行程序如下:
即是一个链表的尾节点的指针指向了链表中的某一个节点,造成了链表的死循环
如何判断一个链表是否为环形链表?
思路:定义两个指针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
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);
}
运行代码如下:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)