在链表学习中,我们已经了解了单链表和双链表,两者的最后一个结点都会指向NULL;今天我们介绍的循环列表则不同,其末尾结点指向的这是链表中的一个结点。
循环链表是一种特殊类型的链表,其尾节点的指针指向头节点,形成一个闭环。与普通链表相比,它没有明确的结束节点,遍历时可无限循环。这种结构特别适合处理循环任务,如音频播放列表循环播放、任务调度等场景,能有效减少节点访问的边界检查,提高操作效率。
在循环链表的题目中,通常会涉及到两个问题:
1.如何判断该链表为循环链表
2.循环链表的循环入口位置。
力扣的142题就是循环链表题,以下是题解与代码:
1、快慢指针寻找是否有环,
1).我们声明两个指针,快指针每次向链表下方走两步,慢指针则走一步;
2).如果有环,则快指针先进入环,慢指针后进入环, 如果无环,则fast会走出循环判断条件,返回空
3).有环时,慢指针进入环后,快指针相对慢指针每次移动一格,也就是快指针会追上慢指针。
4).快指针在一圈内追上慢指针:如果慢指针走一圈,快指针则走了两圈,在这两圈内,快指针一定会与慢指针相遇,所以快指针在一圈内追上慢指针
5).两者相遇时、声明index记录该点。
2、如何判断环的起点
head到起点记为 x;起点到相遇点记为y;相遇点再到起点记为z; 则y+z为环长,
慢指针与快指针所走距离差两倍
x+y=n(y+z)
x=(n-1)(y+z)+z
也就是
入口距离=(n-1)圈长+相遇点到入口的距离
所以我们可以让index 与head同时出发,两者会同时到达入口,(该过程中index肯会绕环未知圈)
struct ListNode {int val;struct ListNode *next;
};
struct ListNode *detectCycle(struct ListNode *head)
{struct ListNode* fast=head,* slow=head;while (fast!=NULL&&fast->next!=NULL){fast=fast->next->next;slow=slow->next;if (slow==fast){struct ListNode* index;index=fast;while (index!=head){index=index->next;head=head->next;}return index;}}return NULL;
}