三类情况:
1、遇到这个问题,首先想到的是遍历链表,寻找是否有相同地址,借此判断链表中是否有环。
listnode_ptr current =head->next;
while(current)
{
if(current==head)
{
printf("有环!\n");
return 0;
}
else
{
current=current->next;
}
}
printf("无环!\n");
return 0;
这段代码满足了(1)(链表无环)、(2)(链表头尾相连)两类情况,却没有将(3)情况考虑在内,如果出现(3)类情况,程序会进入死循环。
2、将(3)考虑在内,首先想到我们可能需要一块空间来存储指针,遍历新指针时将其和储存的旧指针比对,若有相同指针,则该链表有环,否则将这个新指针存下来后继续往下读取,直到遇见NULL,这说明这个链表无环。
上述方法虽然可行,可是否还有更简便的算法?
3、假设有两个学生A和B在跑道上跑步,两人从相同起点出发,假设A的速度为2m/s,B的速度为1m/s,结果会发生什么?
答案很简单,A绕了跑道一圈之后会追上B!
将这个问题延伸到链表中,跑道就是链表,我们可以设置两个指针,a跑的快,b跑的慢,如果链表有环,那么当程序执行到某一状态时,a==b。如果链表没有环,程序会执行到a==NULL,结束。
listnode_ptr fast=head->next;
listnode_ptr slow=head;
while(fast)
{
if(fast==slow)
{
printf("环!\n");
return 0;
}
else
{
fast=fast->next;
if(!fast)
{
printf("无环!\n");
return 0;
}
else
{
fast=fast->next;
slow=slow->next;
}
}
}
printf("无环!\n");
return 0;
4、关于算法复杂度:
如图,链表长度为n,环节点个数为m,则循环 t=n-m 次时,slow进入环中,此时,我们假设fast与slow相距x个节点,那么,经过t'次循环,二者相遇时,有:
2t'=t'+(m-x) -> t'=m-x -> t'<=m.
因此,总共循环了T=t+t' <= n. 算法复杂度为O(n).