看懂环形链表

1.环形链表

  • 环形链表是链表的一种特殊形式,其中链表的某个节点指向链表中已经访问过的另一个节点,形成一个闭环。在普通的单链表或双链表中,链表的末尾节点指向null,表示链表的结束。但在环形链表中,末尾节点(或链表中的任何节点)指向链表中的某个先前节点,从而形成环。

2. 环形链表 I (判断链表是否存在环)

  • 链表作为一种常见的数据结构,由一系列的结点组成,它的节点包含数据和指向下一个节点的指针两部分,但在某些情况下,指向下一个结点的指针会指向前面已经访问过的结点,构成一个环。
  • 快慢指针是一种有效的解决方法(也称为Floyd的循环查找算法或龟兔赛跑算法)。

2.1 快慢指针的原理

原理:快慢指针包括两个指针,一个快指针和一个慢指针,快指针每次移动两个结点,慢指针每次移动一个节点,如果链表中存在环,那么快指针和慢指针就会相遇于某个节点;如果不存在环,那么快指针就会先到达链表的尾。

2.2 检测链表存环

  1. 首先定义两个指针,一个快指针,一个慢指针,并初始化指向链表的头节点
struct ListNode* slow,*fast;
    slow = fast = head;
  1. 然后定义一个循环,让快指针每次移动两个节点,慢指针每次移动一个节点
while(){
        slow = slow->next;
        fast = fast->next->next;
    }

3.如果快指针和慢指针相遇,则说明存在环,返回true

while(){
        slow = slow->next;
        fast = fast->next->next;
        
        if(slow == fast){
            return true;
        }
    }
  1. 确定while循环的结束条件
    如果链表中存在环,那么快指针和慢指针就会相遇于某个节点;如果不存在环,那么快指针就会先到达链表的尾。
    当链表不存在环且结点个数为奇数时,快指针走到尾结点,不能再往后移动;
    当链表不存在环且结点个数为偶数时,快指针走到尾结点的下一个位置,遍历完链表,结束循环;
    所以结束的条件为 fast && fast->next
    while(fast && fast->next){
        slow = slow->next;//慢指针每次移动一个结点
        fast = fast->next->next;//块指针每次移动两个结点

        if(slow == fast){//快慢指针相遇说明存在环
            return true;
        }
    }
  • 力扣相关题目:
    判断链表是否有环

力扣题目完整代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow,*fast;
    slow = fast = head;

    while(fast && fast->next){
        slow = slow->next;
        fast = fast->next->next;

        if(slow == fast){
            return true;
        }
    }
    return false;
}

3.环形链表 II (返回入环处的结点)

  • 当确定了链表存在环,那么下一步就是找到环的入口,即进入环的第一个节点,为了找到环的入口,同样的让快慢指针在相同速度下,快指针一次走两步,慢指针一次走一步,最终快慢指针会相遇,记录相遇点并开始继续向下走,同时让指针从链表起始位置开始遍历,两个指针最终会在环的入口处相遇。
  1. 首先返回环形链表入环结点的前提是有环,所以首先要确定是否有环
  2. 同样的初始化快慢指针,并指向头结点。
struct ListNode* slow = head,*fast = head;
  1. 然后定义一个循环,让快指针每次移动两个节点,慢指针每次移动一个节点
while(){
        slow = slow->next;
        fast = fast->next->next;
    }
  1. 确定while循环的结束条件
    如果链表中存在环,那么快指针和慢指针就会相遇于某个节点;如果不存在环,那么快指针就会先到达链表的尾。
    当链表不存在环且结点个数为奇数时,快指针走到尾结点,不能再往后移动;
    当链表不存在环且结点个数为偶数时,快指针走到尾结点的下一个位置,遍历完链表,结束循环;
    所以结束的条件为 fast && fast->next
    while(fast && fast->next){
        slow = slow->next;//慢指针每次移动一个结点
        fast = fast->next->next;//块指针每次移动两个结点
        }
    }

4.如果快慢指针相等,说明存在环,记录它们相遇的结点为meet,然后让头节点从头开始移动,让meet(即快慢指针相遇的结点)向下一个节点继续移动,因为链表此时已确定有环,那么meethead一定会相遇,此时它们相遇的结点就是环的入口

 while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;

        if(slow == fast)
        {
            struct ListNode* meet = slow;

            while(head != meet)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
  • 力扣相关题目:
    环形链表返回入口处结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
    ListNode* slow = head,*fast = head;

    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;

        if(slow == fast)
        {
            ListNode* meet = slow;//记录快慢指针相遇的位置
			
			//让头结点和快慢指针相遇结点同时移动,它们相遇处即为入口处
            while(head != meet)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

有关环形链表的思考

4.为什么快慢指针在环中一定会相遇,是否可能会错过永远追不上?

5.慢指针slow走1步,快指针fast走3步,走4步…走N步,可不可以?

6.为什么从快慢指针的相遇点,和链表头结点处同时继续向下走,最终会在环的入口处相遇?

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值