环形链表类
问题描述
在一个单向链表中,链表的尾结点指向链表的一个节点(这个节点可以是链表的任意一个节点,包括头结点和尾结点),形成闭环,称为环形链表。
例如:
提示:以下是本篇文章正文内容,下面案例可供参考
一、判断链表是否带环?
提示:
(1)如果直接对环形链表遍历,则会造成死循环。
(2)可以考虑使用快慢指针,由于步长不同快慢指针总会相遇。
代码如下(示例):
/**
* 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)//slow==fast说明相遇,为环形链表
return true;
}
if(fast==NULL||fast->next==NULL)//fast为NULL说明,遍历到了尾结点
{
return false;
}
}
二、判断链表换开始的起点
1.题目分析
(1)快慢指针的步长差距只能为1;
分析:如果步长差距不为1,为2或者其他,由于链表环内的元素个数的原因,步长过大,会增加时间复杂度。
(2)假设起始位置到链表起点的距离为L,环长为C,相遇点距环起点的距离为X。fast指针走的长度为2*(L+X+mC);slow指针走的距离为L+X+nC;(这里可以类比为物理的追及问题,时间为fast走的节点数L+X+mC)
快慢指针的路程相等,即2(L+X+mC)=L+X+nC,得到L+X=K*C,K=2m-n;
2.代码编写
代码如下(示例):
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *slow,*fast;
slow=fast=head;
while(fast&&fast->next) //判断是否带环
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
break;
}
if(fast==NULL||fast->next==NULL)
return NULL;
struct ListNode *meet=fast;//相遇根据推论编写程序
while(meet!=head)//L+X=K* C
{
head=head->next;
meet=meet->next;
}
return meet;
}
总结
环形链表由于自身结构尾部相连的原因,只能使用快慢指针来判断链表是否存在环形结构,同时还需数学推论来支撑程序的算法结构。