一、判断单链表是否有环
原理:就像操场上跑步一样,跑的快的终会套圈(相遇)。因此可以设置两个指针,一个慢的(slow),一个快的(fast),这样若单链表中存在环的话就会相遇。
typedef struct list{
int data;
struct list *next;
}Linklist;
bool Linkklistloop(Linklist *head){
if(head == NULL|| head -> next == NULL)
return false;
Linklist *slow = head;
Linklist *fast = head;
while(fast && fast -> next){
slow = slow -> next;
fast = fast -> next -> next;
if(slow == fast)
return true;
}
return false;
}
二、找到环的入口
原理:链表头到环入口的距离等于(n-1)循环内环+相遇点到环入口点的距离
所以我们在链表头和相遇点分别设置一个结点,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点
Linklist * findLoopPort(Linklist * head){
Linklist *slow,*fast;
slow = head;
fast = head;
while(fast && fast -> next){
slow = slow -> next;
fast = fast -> next -> next;
if (slow == fast)
break;
}
if(fast = NULL || fast -> next =NULL)
return NULL;
slow = head;
while(slow != fast){
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
三、扩展:判断两个单链表是否相交,如果想交的话,给出第一个点(两个链表都不存在环)
比较好的方法有两个:
1.将其中一个链表头尾相连,检测另一个链表是否存在环,存在的话就是相交,而检测出来的环的入口及时相交的第一个结点
2.如果两个链表相交的话,从相交点到尾结点都是相同的结点,所以两个链表都遍历到尾结点,如果可以走到一个相同的尾结点的话,就表示相交。
此时记录下两个链表的长度,在遍历一次,长链表结点先出发(maxlength-minlength)步,之后两个链表同时前进,每次一步,相遇的第一个点既是相交的第一点。