iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言数据结构中单向环形链表怎么实现
  • 118
分享到

C语言数据结构中单向环形链表怎么实现

2023-06-29 23:06:40 118人浏览 独家记忆
摘要

这篇“C语言数据结构中单向环形链表怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言数据结构中单向环形链表怎么实现

这篇“C语言数据结构中单向环形链表怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言数据结构中单向环形链表怎么实现”文章吧。

1、例题引入

链接直达:

环形链表

题目:

C语言数据结构中单向环形链表怎么实现

2、何为带环链表

 正常的单链表每个节点顺次链接,最后一个节点指向NULL,如下:

C语言数据结构中单向环形链表怎么实现

 而带环链表的最后一个节点不再指向NULL了,指向的是前面任意一个节点,以此形成带环链表,并一直循环下去。如下:

C语言数据结构中单向环形链表怎么实现

3、题解思路

我们可以将上述图画的抽象一点,在没有进入环之前我们用直线表示,进入环之后用圈来表示,以此示意循环。此题需要用到我们之前讲解的求中间节点和求倒数第k个节点的快慢指针的思想。定义两个指针slow和fast均指向一开始的位置。 让slow一次走一步,fast一次走两步。

C语言数据结构中单向环形链表怎么实现

当slow走到直线一半的位置时,此时的fast刚好就在环的入口点。

C语言数据结构中单向环形链表怎么实现

假设slow刚好走到环的入口点时,fast走到如下位置,此时fast开始追赶模式

C语言数据结构中单向环形链表怎么实现

 fast开始追赶slow,假设fast在如下的位置开始追上slow

C语言数据结构中单向环形链表怎么实现

代码如下:

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

单纯从解体的角度看,此题并不复杂,仅需用到快慢指针的思想即可解决,单是由此题可以引出多个值得我们探讨的问题,以此来加深我们对环形链表的认知,如下三大拓展问题:

4、拓展问题

  • (1)slow一次走1步,fast一次走2步,一定能追上吗?

 答案:一定能。

证明:

当slow走到中间的时候,fast一定进环了,此时fast开始追击。我们假设slow进环以后,slow和fast的距离是N,此时slow走1步,fast走2步,它们俩的距离缩短1变为N-1。以此类推,每次追击,距离缩小1,当距离缩小为0时就追上了。综上,一定能追上。

C语言数据结构中单向环形链表怎么实现

  • (2)slow一次走1步,fast一次走3步,能追上吗?fast一次走4步呢?n步呢?  

答案:不一定

证明:

我们先来讨论slow一次走1步,fast一次走3步的情况。假设slow走了1步,fast走3步时刚好进环,而当slow刚好进环的时候,fast可能已经走了1圈,具体情况得看环的大小,此时slow和fast之间的距离为N。并假设环的长度是C。

slow一次走1步,fast一次走3步,距离变为N-2。由此可见,fast和slow每走一次,距离缩短2。此时就不难发现了,需要分类讨论,当N是偶数时,刚好可以追上,当N是奇数时,追到最后距离为-1,此时就要再追了,意味着slow和fast之间的距离变成C-1。

继续追击,根据前面的分析,如果C-1是偶数,那么可以追上。如果C-1是奇数,那么就永远追不上了,将会无线循环追下去,可就是追不上。他们的差距N是由进环前的长度和环的长度决定的,而这两个又都是随机的,所以N的值不确定,可奇可偶,又像刚刚那样讨论下去,出现奇数将一去不复返。

C语言数据结构中单向环形链表怎么实现

同理fast一次走4步也是这样的讨论,同样都是不一定,不过这个时候是每走一次,距离缩短3。当N是3的倍数就可以追上,当不是3的倍数就要继续讨论了,有兴趣的童鞋可以继续钻研下去,思想和fast一次走3步一样,这里不过多赘述。

  • (3)链表环的入口点在哪呢?

 当我们搞清楚slow和fast分别走的距离时,入口点自然就明了了。

法一:

C语言数据结构中单向环形链表怎么实现

slow一次走1步,fast一次走2步,那么fast走的距离是slow的2倍

在具体讲解之前,首先要搞清楚,不存在说慢指针slow在里头走了一圈,快指针fast还没有追到slow,因为fast每次走2步,slow每次走1步,它俩间的距离每次都缩小1,所以只会越来越近,直到追到。最多最多也就快1圈,但从来也不会刚好满1圈。所以下面很容易推出slow和fast分别走了多少。

假设:

【链表头 - - - 入口点】:L

【入口点 - - - 相遇点】:X

【环的长度】:C

C语言数据结构中单向环形链表怎么实现

slow走的距离:L + X

fast走的距离:L + N*C + X

解释:

因为先前已经提到slow不会都走了一圈还没被追到,所以很容易推出slow的距离就是L+X

而快指针一次走2步,很可能会因为环过小导致在slow指针进入入口点前,fast指针已经走了好几圈。简而言之3句话:

  • L很小,C很大,slow进环前,fast可能在环里面,一圈都没走完

  • L很大,C很小,slow进环前,fast在里面走了很多圈了

  • 但是slow进环以后,在一圈之内,fast一定追到slow,它们的距离最多C-1

根据一开始说的,fast走的距离是slow走的距离的2倍,可列出如下式子:

2*(L+X) = L + N*C + X

化简后:L+X = N*C     或    L = N*C - X     或     L = (N-1)*C + (C-X)     或     L + X = N*C

用此公式即可证明:一个指针从meet走,一个指针从head走,他们会在入口点相遇!

因为式子(N-1)*C表明从相遇点走了N-1圈后又回到了相遇点,此时再走C-X的距离就回到了入口点,由上得知,此公式确实让它们回到了入口点。

用一道切实的题目来具体解出入口点的位置:链接直达:

环形链表2.0-->寻找入口点

题目:

C语言数据结构中单向环形链表怎么实现

 代码如下:

struct ListNode* detectCycle(struct ListNode* head) {    struct ListNode* slow = head;    struct ListNode* fast = head;    while (fast && fast->next)    {        //判断是否是带环链表        slow = slow->next;        fast = fast->next->next;        if (slow == fast)        {            struct ListNode* meet = slow;            while (meet != head)            {                //求出相遇点                meet = meet->next;                head = head->next;            }            return meet;        }    }    return NULL;}

求相遇点还有另外一种方法:

找到相遇点meet后,让meet做尾,让下一个点做新链表的头

C语言数据结构中单向环形链表怎么实现

以上就是关于“C语言数据结构中单向环形链表怎么实现”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网其他教程频道。

--结束END--

本文标题: C语言数据结构中单向环形链表怎么实现

本文链接: https://www.lsjlt.com/news/326808.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c语言怎么计算字符串长度
    在C语言中,可以使用内置的strlen()函数来计算字符串的长度。该函数位于string.h头文件中。以下是一个示例代码: #inc...
    99+
    2024-05-15
    c语言
  • c语言怎么判断三个数的大小
    可以通过比较三个数之间的大小关系来判断它们的大小。以下是一个示例代码: #include <stdio.h> int ...
    99+
    2024-05-15
    c语言
  • c++排序函数sort怎么使用
    在C++中,使用sort函数对容器中的元素进行排序,可以按照默认的升序排列,也可以自定义排序规则。 下面是一个简单的例子,对一个ve...
    99+
    2024-05-15
    c++
  • c++中string的compare函数怎么使用
    在C++中,可以使用string的compare函数来比较两个string对象的大小。该函数的原型如下: int compare(c...
    99+
    2024-05-15
    c++
  • c++中string的compare函数有什么用
    c++中string的compare函数用于比较两个字符串的大小关系。该函数返回一个整数值,表示两个字符串的比较结果。 具体来说,如...
    99+
    2024-05-15
    c++
  • c++中print函数的功能有哪些
    在C++中,通常使用std::cout来进行输出操作,而不是使用print函数。std::cout是C++标准库中的一个输出流对象,...
    99+
    2024-05-15
    c++
  • c语言数据结构怎么使用
    在C语言中,数据结构可以通过定义结构体来实现。以下是一些常见的数据结构的使用方法示例: 链表: #include <std...
    99+
    2024-05-15
    c语言
  • c++中print函数的用法是什么
    在C++中没有内置的print函数,但可以使用cout来输出内容到控制台。cout是C++标准库中的一个输出流对象,可以使用<...
    99+
    2024-05-15
    c++
  • c++中concept的用法是什么
    在C++20中,Concept是一种新的语言特性,用于定义类型要求和约束。Concept可以被用来约束函数模板、类模板和普通函数的参...
    99+
    2024-05-15
    c++
  • c++中concept的作用是什么
    在C++中,concept的作用是定义一种通用的约束,用于限制模板参数的类型范围。通过使用concept,可以在编译时对模板参数进行...
    99+
    2024-05-15
    c++
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作