判断单链表是否为有环链表


有环链表并不一定就是循环链表。循环链表指的是“首尾相连”的单链表,而有环链表则指的是单链表中存在一个循环子链表,如下图所示是有环链表,但并不是循环链表:

在这里插入图片描述
如果给定一个单链表,如何判断其是否为有环链表呢?常用的判断方法有 2 种。

1. 方法一

从给定链表的第一个节点开始遍历,每遍历至一个节点,都将其和所有的前驱节点进行比对,如果为同一个节点,则表明当前链表中有环;反之,如果遍历至链表最后一个节点,仍未找到相同的节点,则证明该链表中无环。

注意,如果一个单链表为有环链表,基于单链表中各节点有且仅有 1 个指针域的特性,则势必该链表是没有尾结点的。换句话说,有环链表的遍历过程是无法自行结束的,需要使用 break 语句手动结束遍历。

C语言实现代码如下:

//自定义 bool 类型
typedef enum bool
{
    False=0,
    True=1
}bool;
// H 为链表的表头
bool HaveRing(link * H) 
{
    link * Htemp = H;
    //存储所遍历节点所有前驱节点的存储地址,64位环境下地址占 8 个字节,所以这里用 long long 类型
    long long addr[20] = { 0 };
    int length = 0, i = 0;
    //逐个遍历链表中各个节点
    while (Htemp) 
    {
        //依次将 Htemp 和 addr 数组中记录的已遍历的地址进行比对
        for (i = 0; i < length; i++) 
        {
            //如果比对成功,则证明有环
            if (Htemp == addr[i]) 
            {
                return True;
            }
        }
        //比对不成功,则记录 Htemp 节点的存储地址
        addr[length] = Htemp;
        length++;
        Htemp = Htemp->next;
    }
    return False;
}

当函数的返回值为 True,表示该链表有环;反之若函数返回值为 False,表明链表中无环。此实现方案的时间复杂度为O(n2)

2. 方法二

该算法的实现思想需要借助一个论点,即在一个链表中,如果 2 个指针(假设为 H1 和 H2)都从表头开始遍历链表,其中 H1 每次移动 2 个节点的长度(H1 = H1->next->next),而 H2 每次移动 1 个节点的长度(H2 = H2->next),如果该链表为有环链表,则 H1、H2 最终必定会相等;反之,如果该链表中无环,则 H1、H2 永远不会相遇。

有关在有环链表中 H1 和 H2 必定会相遇的结论,假设有环链表中的环包含 n 个节点,则第一次遍历,H1 和 H2 相差 1 个节点;第二次遍历,H1 和 H2 相差 2 个节点;第三次遍历,H1 和 H2 相差 3 个节点…,最终经过多次遍历,H1 和 H2 会相差 n-1 个节点,此时就会在环中重合,此时 H1 和 H2 相等。

基于以上这个结论,编写出对应的实现代码:

//H为链表的表头,该函数会返回一个枚举的 bool 类型数据
bool HaveRing(link * H) 
{
    link * H1 = H->next;
    link * H2 = H;
    while (H1)
    {
        if (H1 == H2)
        {
            //链表中有环
            return True;
        }
        else
        {
            H1 = H1->next;
            if (!H1)
            {
                //链表中无环
                return False;
            }
            else
            {
                H1 = H1->next;
                H2 = H2->next;
            }
        }
    }
    //链表中无环
    return False;
}

当函数返回 False 时,表明当前链表中无环;反之若返回 True,则表明该链表为有环链表。本算法的时间复杂度为 O(n)

  • 6
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 是的,在一个有环链表中,slow 和 fast 有永远无法相遇的可能。这是因为在链表中,slow 和 fast 指针会以不同的速度移动,而当 slow 指针每次移动一个节点,fast 指针则会移动两个节点。如果的大小为 N,那么当 slow 指针走了 N 个节点之后,fast 指针会走 2N 个节点,此时 fast 指针又回到了的起点,而 slow 指针则留在原地。这样,slow 和 fast 指针就永远无法相遇了。 ### 回答2: 在一个有环链表里,slow和fast无法相遇的情况是可能的。一个有环链表是指链表中存在一个形结构,即链表的最后一个节点指向之前的某一个节点。而slow和fast是分别以不同的速度在链表上移动的指针。 如果在移动过程中,fast始终能够在slow之前到达链表的尾部,则它们永远不会相遇。这是因为fast的速度比slow快,所以fast可以在一次迭代中跳过多个节点。即使slow在内循,fast仍然可以快速追上或超过slow。 此外,如果链表中的是非常大且slow和fast的速度足够慢,也存在无法相遇的情况。即使他们始终都在中移动,由于速度过慢,slow可能永远无法追上fast。 综上所述,在一个有环链表里,slow和fast有可能永远无法相遇。这通常取决于fast的速度和slow与fast的相对位置。 ### 回答3: 在一个有环链表中,slow和fast有永远无法相遇的可能性是存在的。这种情况通常发生在的长度比链表长度还要长时。 当slow和fast同时进入中时,fast的速度通常比slow快。每次移动,fast都会在链表中多前进一个节点,而slow只前进一个节点。如果的长度较小,那么fast最终必定会追上slow,并且二者会相遇。 然而,当的长度较长时,fast的速度可能会比slow快得更多。在快速移动的同时,fast也会在中绕圈子。如果fast绕了n圈后才追上slow,那么此时slow和fast之间的距离就是的长度的n倍。由于的长度比链表长度还要长,所以在经过n次迭代后,fast将继续在中绕圈子追赶slow,从而无法相遇。 综上所述,在有环链表中,如果的长度比链表长度还要长,那么slow和fast有永远无法相遇的可能性是存在的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值