给定一个单链表,只给出头指针h:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
解法:
1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。
3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。
该定理的证明可参考:http://fayaa.com/tiku/view/7/
4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度
- #include <stdio.h>
- typedef struct Node
- {
- int val;
- Node *next;
- }Node,*pNode;
- //判断是否有环
- bool isLoop(pNode pHead)
- {
- pNode fast = pHead;
- pNode slow = pHead;
- //如果无环,则fast先走到终点
- //当链表长度为奇数时,fast->Next为空
- //当链表长度为偶数时,fast为空
- while( fast != NULL && fast->next != NULL)
- {
- fast = fast->next->next;
- slow = slow->next;
- //如果有环,则fast会超过slow一圈
- if(fast == slow)
- {
- break;
- }
- }
- if(fast == NULL || fast->next == NULL )
- return false;
- else
- return true;
- }
- //计算环的长度
- int loopLength(pNode pHead)
- {
- if(isLoop(pHead) == false)
- return 0;
- pNode fast = pHead;
- pNode slow = pHead;
- int length = 0;
- bool begin = false;
- bool agian = false;
- while( fast != NULL && fast->next != NULL)
- {
- fast = fast->next->next;
- slow = slow->next;
- //超两圈后停止计数,挑出循环
- if(fast == slow && agian == true)
- break;
- //超一圈后开始计数
- if(fast == slow && agian == false)
- {
- begin = true;
- agian = true;
- }
- //计数
- if(begin == true)
- ++length;
- }
- return length;
- }
- //求出环的入口点
- Node* findLoopEntrance(pNode pHead)
- {
- pNode fast = pHead;
- pNode slow = pHead;
- while( fast != NULL && fast->next != NULL)
- {
- fast = fast->next->next;
- slow = slow->next;
- //如果有环,则fast会超过slow一圈
- if(fast == slow)
- {
- break;
- }
- }
- if(fast == NULL || fast->next == NULL)
- return NULL;
- slow = pHead;
- while(slow != fast)
- {
- slow = slow->next;
- fast = fast->next;
- }
- return slow;
- }