求链表的中间值
list 中一般有 size 这个成员数属性,要求链表的中间值,只要遍历 size/2 次即可,但是如果没有这个 size 属性该如何求链表的中间值呢?
可以定义两个指针,开始都指向链表的头节点,然后慢指针每次移动一个节点,快指针每次移动两个节点,当快指针移动到元素末尾时,慢指针刚好指向链表的中间。
原理: 快指针是慢指针的两倍,快指针走完时慢慢指针当然走了一半,这个很好理解
判断单向链表是否有环
可以定义两个指针,开始都指向链表的头节点,然后慢指针每次移动一个节点,快指针每次移动两个节点,如果快慢指针会相遇则说明单链表有环
原理:
两个人绕圈跑,快的人一定会追上慢的人,且至多追一圈的距离(追一圈的距离等于快指针跑两圈,慢指针跑一圈,也就是两人一旦都在圈内,从此时开始算,快的最多还需要跑两圈就一定能遇到慢的)
为什么不会“错过”?
因为快指针每次走两步,慢指针每次走一步,也就是快指针和慢指针每次走相差步数是1,当两指针都在环内时,快指针每次都能追上慢指针1步,迟早会追上。如果步迈相差 不是1 那才可能会“错过”。
那快指针至少和至多追多少次能追上慢指针呢?
四种情况: 这里 n = 1,2,3 …
- 快指针走完所有节点后第 n 次走到或走过环的连接点时,慢指针还没进入环(走到或走过连接点)
那快指针继续走,等到慢指针进入环后(走到或走过连接点)才开始追 - 快指针走完所有节点后第 n 次走到或走过环的连接点时,慢指针已进入环了(走到或走过连接点),且刚好和快指针相遇(可能在环的任何位置)
那此时就不用追了,即 0 次 - 快指针走完所有节点后第 n 次走到或走过环的连接点时,慢指针已进入环了(走过或走到连接点),且此时慢指针刚好在快指针后一节点,那就要追 环的长度-1 次
- 特殊情况:一开始快指针和慢指针都在环内(循环链表),快指针走完所有节点后第 1 次走到或走过环的连接点时,慢指针在环的中间位置,此时要追 环的长度/2 次
结论:两指针都进入环后,至少一次都不用追,至多追 环的长度-1 次。
求有环单链表的环长
从第一次相遇后开始,再次相遇时慢指针走过的步数就是环的长度。
原理:
两人步迈相差两倍,同时从环内某点出发,再次相遇时,快的走了2圈,慢的走了1圈,想要求环的长度,也就刚好是慢指针走过的长度,请结合上面快指针追慢指针的第二种情况和第三种情况理解。
求单链表有环时的连接点
相遇后,慢指针从相遇点出发,再设一个慢指针从头节点出发,当两慢指针再相遇时的那个点就是连接点。
原理:相遇点正向到连接点的距离 = 头指针到连接点的距离,推导如下
求单链表有环时的总长度
链表总长度 = 环的长度 + 头节点到环的连接点的距离(包含头节点不包含连接点)



