C语言——环形链表详解

什么是带环链表

在一个单链表中,链表中存在环形结构。
在这里插入图片描述
在链表中的某个节点,可以连续通过next指针再次到达,则链表中存在环。

检测链表是否带环

我在最开始判断链表是否带环时,是这样一种思路:
通过连续跟踪next,看next能不能等于我标记的节点,如果等于,那么这就是一个带环链表。
这个方法并不可行,因为能不能再次走到标记的节点,在于标记的节点在不在环里,如果不在环里,那么就永远找不到。
有可能像上图一样很快就进环,也有可能像这样:
进环前的前缀比较长。
在这里插入图片描述

判断方法:

使用快慢指针:
快指针一次性往后走两个节点,慢指针一次走一个节点。
判断快指针和慢指针是否相遇,如果相遇,就代表链表中存在环。
画图更清晰:
在这里插入图片描述

代码也是非常简单:

 bool hasCycle(struct ListNode *head) {
    ListNode* slow = head;
    ListNode* fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(fast == slow)
        {
            return true;
        }
    }
    return false;
}

fast和slow会不会错过

为什么fast和slow一定会相遇,有没有可能错过,永远追不上?

当fast走两步时

我们这里先用fast走两步,slow走一步为例:
在这里插入图片描述

fast追击slow的过程中距离的变化如下:
N
N-1
N-2
……
2
1
0
也就是说,每追击一次,他们的距离就缩短1,直到距离为0追上。

——————————————————————————————————————————
如果slow走一步,fast走三步,四步,五步呢,还能追的上吗?
我们用同样的方法分析一下:

当fast走三步时

在这里插入图片描述

当fast进环时,fast和slow的距离为N
fast追击slow的过程中距离变化如下:
N为偶数:
N
N-2
N-4
……
4
2
0 (追上了)

在这里插入图片描述
——————————————————————————————————————————

N为奇数:
N
N-2
N-4
……
3
1
-1(错过了)
在这里插入图片描述
这里又要开始新一轮的追击。
我么假设环的长度为C
这时距离变成了N=C-1

结论:

当fast走两步时,一定能追上slow
当fast走三步时

  1. 如果N为偶数,直接追上
  2. 如果N为奇数,继续追击,这里还要再分成两个情况
    1)C-1是偶数,就又回到了N为偶数的问题,新一轮追击将会追上
    2)C-1是奇数,出现死循环,永远错过

——————————————————————————————————————————

当fast走四步时

fast追击slow的过程中距离变化如下:

  1. N为三的倍数
    N
    N-3
    N-6
    ……
    6
    3
    0(追上了)

——————————————————————————————————————————

  1. N不为三的倍数
    a、N % 3 == 2
    N
    N-3
    N-6
    ……
    4
    1
    -2
    那么这里又有两种情况:
    C-2是偶数,就又回到了N为偶数的问题,新一轮追击将会追上
    C-2是奇数,出现死循环,永远错过

b、N % 3 == 1
N
N-3
N-6
5
2
-1
那么这里还是有两种情况:
C-1是偶数,就又回到了N为偶数的问题,新一轮追击将会追上
C-1是奇数,出现死循环,永远错过

总结:

无论slow走几步,fast走几步,追击问题关系的不是走几步,而是速度差,因为他们最终都会进环。

我们回到原来的问题,fast和slow到底会不会错过。
当fast走三步,slow走一步时为例:
如果同时存在N是奇数且C是偶数,那么将永远追不上。但是,有没有一个可能,这种情况不存在。
我们使用数学来证明一下。
在这里插入图片描述

假设slow进环时fast跟slow的距离为N
slow走的距离为L
fast走的距离为L + xC + C - N(slow进环时,假设fast已经转了x圈)
因为fast走的距离时slow的三倍
3
L = L + Cx + C - N
简化一下:
2
L = Cx + C - N
2
L = C*(x+1) - N

2乘任何数都为偶数,所以2L一定为偶数,上面说到:
“如果同时存在N是奇数且C是偶数,那么将永远追不上。但是,有没有一个可能,这种情况不存在。”
2
L = C*(x+1) - N:
偶数 = (x+1) * 偶数 - 奇数
这种情况不可能存在!!!只有奇数减去奇数才能为偶数, “(x+1) * 偶数” 一定是偶数。
所以“N是奇数且C是偶数”不能同时存在,总会追击上的。

希望这篇博客对你有所帮助!!!
在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值