环形链表
![在这里插入图片描述](https://img-blog.csdnimg.cn/0b6bbf2323e1406186056a5830389eea.png#pic_center
问题分析
- 循环链表
尾节点指向头节点,头节点指向尾节点,头节点的指针域往复遍历会指向尾节点,造成循环,它的循环域是整个链表。
- 环形链表
尾节点指向链表中的某一节点,某一节点的指针域往复遍历会指向尾巴节点,造成循环,它的循环域是某一节点到尾节点之间
解决方案
- 快慢指针
解题分析
-
要求
判断链表是否带环,带环返回true,否则返回false
-
思路
首先设置一个快指针和一个慢指针,快指针遍历一次指向它下一个节点,慢指针遍历两次指向它下一个节点的下一个节点,当第一次快指针指向最后一个节点的时候那它下一个节点就是尾节点指向的某一节点,这一节点会往复遍历指向尾节点,造成循环,当慢指针第一次进入循环跟快指针同理,但是有一点不同,就是,快指针它一次走两步,而慢指针一次只走一步,当两个指针同时进入循环时,他们之间的距离是1,所以快指针每走一步都会比慢指针多一步,让这两个指针在环里进行追逐,快指针追慢指针,最终让快指针与慢指针相遇,快指针和慢指针同时指向一个节点,快指针等于慢指针,
-
语句
节点结构体创建
struct ListNode
{
int val;
struct ListNode* next;
};//
实现接口
这里要求返回一个bool类型的返回值来判断结果,但是在C89标准下是没有bool类型的,因为这里给的是一个接口型所以没有,太注意细节,如果是在IO型下实现该题那么应该引入C99的bool库;这里的形参是一个头节点。
bool HuanXingList(struct ListNode* head)
{
struct ListNode* fast = head;//定义快指针
struct ListNode* slow = head;//定义慢指针
//同时定义为struct ListNode* slow = head,*fast = head;
while(fast && fast->next)//如果快指针不为空,且指向的下一个节点也不为空那么我们判定不为单链表,具有循环
{
slow = slow->next;//慢指针指向下一个节点,走一步
fast = fast->next->next;//快指针指向下一个节点的下一个节点,走两步
if(fast == slow)//如果循环下来让快指针追逐慢指针,让快指针与慢指针相等
return true;//返回为真,说明有环
}
return false;//循环结束没有让快指针与慢指针相等,说明没有环
}
解题实例
提出问题
- slow一次1步,fast一次2步
- 请证明slow和fast一定会在环里相遇?有没有可能不会相遇?
结论:一定能追上
解:因为slow进环了之后,fast才开始正式开始追,假设slow进入环,它与fast之间的距离是N,那么,slow一次一步,fast一次两步,他们之间的距离差是N-1,一直遍历循环N-1、N-2、N-3…,追逐过程中距离都是减1,最终会减到N-0,那也就找到了慢指针slow。
- slow一次1步,fast一次3步
- 请证明slow和fast一定会在环里相遇?有没有可能不会相遇?
结论:有可能死循环,一直追不上slow指针
解:它与fast之间的距离还是N,那么,slow一次一步,fast一次三步,他们之间的距离差是N-2,一直遍历循环N-2,N-4,N-6…,追逐过程中距离都是减2,最终会减到N-(-1),这样导致slow反超fast,那就很有可能追不上fast,要保证fast追上slow那就要看N这个距离的基数了,如果N是偶数,那么在它上面跑最终结果递减还是偶数,如果N是奇数,那么在它上面跑递减就是基数了,结果显然可以找到我们的slow,因此fast一次走n步,自己本身和N的奇偶关系很重要。