环形链表的详解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、环形链表是什么?

简单来说:就是带环的链表(具有环形结构的链表)

如图所示 的俩个链表都是环形链表 

二、环形链表的相关问题

目录

一、环形链表是什么?

二、环形链表的相关问题

1.我们该怎么判断环形链表?

2.环形链表的环形入口点该怎么确定

总结

结论:


1.我们该怎么判断环形链表?

方法:快慢指针(fast and slow)

慢指针:一次走一步 快指针:一次走俩步 (至于为什么一般的快指针一般走俩步,后面会做出解释)

大概思路变化图为:(忽略画工)

 接着slow往前走一步走到节点1处,fast往前走俩步走到节点2处 

 fast再移动俩步,就会进入环中,从2走到0再走到1,slow则是继续往前挪动到第二个2位置处,接下来很容易就会看出slow和fast会在0节点处汇合

 即为下图

 具体代码:

 //快慢指针
bool hasCycle(struct ListNode *head) {
    struct ListNode*slow=head,*fast=head;
    while(fast&&fast->next)//处理奇偶个节点
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

 其中为什么循环的出口为什么是fast和fast->next,是因为如果链表没有环状时,如果链表含有奇数个节点,那么循环会从fast->next走出,此外链表中有偶数个节点就会从fast走出(如果此时将fast->next放在&&前面会报错,因为fast=NULL,而NULL->NULL,是不被系统允许的。)

到这,我相信你们也会和我有一样的疑惑,就是为什么快指针是一次走俩步,而不能走n步呢?(n>2),且为什么环状链表,快慢指针就一定会相遇呢?

下面给出证明:

 

而升序n=4,n=5....的情况都是类似推导的 

2.环形链表的环形入口点该怎么确定

由上文,我们可得知,快慢指针是一定会在有环状结构的链表中的环中相遇。而我们的思路就是从此推出来的结论:从头节点出发的指针一定会和从快慢指针相遇点出发的指针汇合于环入口点。

 


 最后再赋上我的代码(可优化)


 //思路1 :推论:一个从头节点出发的指针和一个从快慢指针的相遇节点出发的指针最后会在入口节点相见
struct ListNode *detectCycle(struct ListNode *head) {
    if(head==NULL||head->next==NULL)
        return NULL;
    struct ListNode*slow=head,*fast=head;
    while(fast&&fast->next)
    {
            fast=fast->next->next;
            slow=slow->next;
            if(slow==fast)
            {
                break;
            }
    }
    if(fast!=slow)
        return NULL;
    struct ListNode* meetNode=fast;//or slow
    struct ListNode* find=head;
    while(meetNode!=find)
    {
        meetNode=meetNode->next;
        find=find->next;
    }
    return meetNode;
}

总结

结论:

  1. 快指针一次走俩步一定会和慢指针在环中相遇,一次走N步时需要进行讨论
  2. 从头节点出发的指针一定会和从快慢指针相遇点出发的指针汇合于环入口点。

以上就是我对环形链表学习的一些心得,也是我的第一篇博客,大家多多指教,欢迎讨论和指正我的错误。

以下是俩道题的链接,帮助我们巩固知识

https://leetcode-cn.com/problems/linked-list-cycle/description/

 https://leetcode-cn.com/problems/linked-list-cycle-ii/description/

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Linux内核中的链表是一种常用的数据结构,它在内核中被广泛使用来组织和管理数据。链表使用双链表的形式,每个节点只包含指针域,没有数据域。在Linux内核中,链表的操作接口定义在`linux/list.h`头文件中。为了方便使用,内核提供了多种初始化链表的方式。宏定义是一种常用的初始化链表的方式,其中的一个宏定义是`INIT_LIST_HEAD(ptr)`。这个宏被用来初始化一个链表节点,将其next和prev指针都指向自身,表示这是一个空链表。通过这样的方式,可以方便地对链表进行插入和删除操作,以及遍历链表中的元素。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Linux内核链表理解与使用](https://blog.csdn.net/to_be_better_wen/article/details/127720433)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [linux内核链表最细讲解](https://blog.csdn.net/yzw_yy/article/details/130094799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Linux中的内核链表实例详解](https://download.csdn.net/download/weixin_38724363/14893522)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值