关于链表是否有环,其实是一系列问题,主要包括以下几个:
1.判断单链表是否有环:
使用快慢指针fast和slow,fast每次走两步,slow每次走一步,如果有环,肯定会相遇,如果没有,则指针fast遇到NULL退出。追及相遇问题。
2.求有环单链表的环长
在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长。
设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:
环长=2*len-len
3.求有环单链表的环连接点位置
第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R。
第一次相遇时,slow走的长度 S = LenA + x;
第一次相遇时,fast走的长度 2S = LenA + n*R + x;
所以可以知道,LenA + x = n*R; LenA = n*R -x;
4.求有环单链表的链表长
上述2中求出了环的长度;3中求出了连接点的位置,就可以求出头结点到连接点的长度。两者相加就是链表的长度。
5.如果快指针每次走三步,四步,五步...会怎么样?
不管快指针走多少步,只要有环就会与慢指针相遇,因为慢指针每次都走一步。但是如果快指针每次走三步以上,就会导致上述公式不成立。比如说快指针每次走三步,则公式变为:
第一次相遇时,slow走的长度 S = LenA + x;
第一次相遇时,fast走的长度 3*S = LenA + n*R + x;
所以可以知道,2*LenA + 2*x = n*R; LenA = n*R/2 -x;
举例:头结点之后就是环的入口,环除了入口还有一个节点,fast每次走三步,slow每次走一步,第一次会在环的入口相遇,分别从第一次碰撞点Pos、头指针head开始走,无法相遇。
参考文献:
https://www.cnblogs.com/xudong-bupt/p/3667729.html