什么样的是带环单链表?什么样的是不带环单链表?
带环单链表就是单链表的尾结点有连接到单链表自身的某一个结点构成了环。
首先,我们怎样检测一个单链表是否带环?
1.检测单链表是否带环
如果链表不带环,可以通过遍历链表找到尾节点;那如果单链表带环,就找不到链表得到尾部了,如果遍历一个带环链表,程序就会陷入死循环。
那怎么办呢?
可以利用快慢指针的思想。定义两个指针都指向链表的头指针,然后遍历链表,让一个指针每次走两个节点,让另一个指针每次走一个节点,这样两个指针在入环前的一段距离是不可能追上的,且入环后快指针和慢指针一定会相遇,则可得若两个指针若在遍历一段后相遇,则带环;若直到走到尾结点,慢指针还没有追上快指针,那么一定是不带环。
//检测链表是否带环
pNode CheckCycle(pList plist) //参数是:链表的头指针
{
pNode fast = plist;
pNode slow = plist;
while (fast != NULL&&fast->next != NULL) //若条件成立,则快指针走到尾结点了,说明是无环
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow) //若条件成立,快慢指针则在环上相遇,说明有环
{
return slow;
}
}
return NULL;
}
2.若有环求环的长度
通过上面函数可以检测是否带环,如果带环,则返回的是一个相遇点的结点,可以通过这个结点来解这道题
因为已经带环,则从这个相遇点出发,当再次回到这个结点时,便刚好在环上走了一圈,则可计算出环的结点数
//若有环, 求环的长度
int GetCircleLength(pList plist) //参数是:检查是否带环的函数里的快慢指针的相遇点 即int GetCircleLength(CheckCycle(plist));
{
pNode cur = plist;
int count = 0;
while(1)
{
cur = cur->next;
count++;
if (cur == plist) //这里遍历链表,从相遇点出发,再回到相遇点便是一圈
{
return count;
}
}
}
3.若有环,找出环的入口点
求环的入口点需要上面两个函数的帮助,要借助相遇点meetNode和环的节点数K来进行一些推理,看下图
看代码:
pNode GetNode(pList plist, pNode meetNode) //pilst:链表头指针 meetNode快慢指针在环上的相遇点
{
pNode cur = plist;
while (cur != meetNode) //在入口点相遇时,条件成立
{
cur = cur->next;
meetNode = meetNode->next;
}
return cur;
}
下面我们看几中链表相交的情况:
怎么判断两条不带环的链表是否相交呢?
很简单,可以遍历两个链表,找到尾结点,看两个链表的尾结点是否相等,若相等则相交;反之,不相交
代码如下:
int CheckCross(pList list1, pList list2)
{
if (list1 == NULL || list2 == NULL)
{
return 0;
}
while (list1->next != NULL)
{
list1 = list1->next;
}
while (list2->next != NULL)
{
list2 = list2->next;
}
if (list1 == list2)
{
return 1;
}
else
{
return 0;
}
}
还没有完!!!!想一想若相交,怎样找到相交点?
我们已经知道带环单链表环的入口结点怎么找,那就应该知道怎么找两个链表的相交点
可以把两条相交链表的尾部结点连接到某一个链表的头部,这样就构成了一个带环的单恋表;
如下图,这时两条链表的交点就变成了带环的单链表环的入口点,便可用上面的方法求得
这里的代码就不贴了,都是可以根据上面的代码完成,有兴趣可以动手敲一下
判断连个带环链表相交分三种情况:不向交,相交且入口点相同,相交但入口点不同
怎么判断两条带环链表是否相交?
首先,可以通过上面的方法找到每个链表环的入口结点,判断一个链表上环的入口结点是否在另一个链表上,若在则链表相交;反之不相交
如果相交,又分为上图2和3两种情况,那怎么区分呢?
2: 相交且入口点相同 3:相交但入口点不同
判断的方法也很简单,我们判断链表是否带环时得到了一个相遇结点,这个结点在环上,可以从这个结点出发,把环遍历一遍,判断结点是否与两个链表的入口结点相等,若两个入口结点都在环上则是情况3;反之情况2
代码也是根据上面的一些函数可以完成