单链表中是否有环(长度和连接点)

来源:互联网 发布:魔兽世界 70数据库 编辑:程序博客网 时间:2024/06/04 19:55
    给定一个单链表,只给出头结点指针pHead:    (1)如何判断链表中是否存在环。    (2)如何知道环的长度。    (3)如何找出环的连接点。    (4)带环链表的长度。    问题一,我们设置两个指针slow和fast,slow指针每次只走一步,fast指针每次走两步,如果fast指针可以追赶上slow指针,也就是说fast指针和slow指针相等。那么我们就说链表中存在环,否则,当fast指针为空时,我们说链表中不存在环。
bool isLoop(ListNode *pHead){//链表是否为空if(pHead == NULL)return false;ListNode *slow = pHead;//一次只走一步的指针ListNode *fast = pHead;//一次走两步的指针while(fast && fast->next){slow = slow->next;//走一步fast = fast->next->next;if(slow == fast)//如果两个指针相等,返回true{return true;}}return false;}
问题二:在问题一的基础上,我们找到slow指针和fast指针相遇点即碰撞点。我们从碰撞点开始,每次走一步,直到再次回到出发点,所走过的步数即为环的长度。当链表中不存在环时,返回环的长度为零。
int lenLoop(ListNode *pHead){if(pHead == NULL)return 0;ListNode *slow = pHead;ListNode *fast = pHead;while(fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow == fast){break;}}//当链表中不存在环时返回长度为零if((fast == NULL) || (fast->next == NULL))return 0;int len = 1;while(slow->next != fast){len++;slow = slow->next;}return len;}
问题三:我们可以根据碰撞点到连接点的距离等于头指针到连接点的距离,我们可以分别从碰撞点和头指针开始,当两个指针相遇时,相遇的位置即连接点的位置。我们可以简单的证明一下,当slow指针和fast指针第一次相遇时,slow指针走过的长度为S,那么fast指针所走过的长度为2S,我们假设从头指针到连接点的距离为lenA,从连接点到碰撞点p的距离为lenP,假设环的长度为R,那么:
S = lenA + lenP;
2S = lenA + n*R + lenP;
由以上可以得到:
lenA = n*R - lenP;
因此碰撞点到连接点的距离等于头指针到连接点的距离。(可能访问环多次)。
//带环链表中的链接点,如果不存在环则返回空指针ListNode * getJoin(ListNode *pHead){if(pHead == NULL)return NULL;ListNode *slow = pHead;ListNode *fast = pHead;while(fast->next){slow = slow->next;fast = fast->next;if(fast->next){fast = fast->next;}else{return NULL;}if(fast == slow){while(slow != pHead){slow = slow->next;pHead = pHead->next;}return slow;}}return NULL;}
问题四:我们在问题二已经求出链表中环的长度,在问题三中我们求出连接点的位置,那么链表的长度等于链表中环的长度和从头指针到连接点距离之和。返回带环链表的长度,如果不存在环,则返回链表的长度。
int getLenLoopList(ListNode *pHead){if(pHead == NULL)return 0;ListNode *slow = pHead;ListNode *fast = pHead;int len = 1;while(fast->next){slow = slow->next;len++;fast = fast->next;if(fast->next){fast = fast->next;}else{return (len - 1) * 2;}if(slow == fast){int len1 = 1;int len2 = 0;ListNode *pos = slow;while(slow->next != fast){slow = slow->next;len1++;}while(pos != pHead){pos = pos->next;pHead = pHead->next;len2++;}return len1 + len2;}}return len * 2 - 1;}
完整版代码:
#include<iostream>using namespace std;struct ListNode{int val;ListNode *next;};void appendTail(ListNode **pHead,int val){ListNode *pNew = new ListNode;pNew->next = NULL;pNew->val = val;if(*pHead == NULL){*pHead = pNew;}else{ListNode *tmp = *pHead;while(tmp->next){tmp = tmp->next;}tmp->next = pNew;}}void show(ListNode *pHead){while(pHead){cout<<pHead->val<<endl;pHead = pHead->next;}}//创建一个带环的链表void createLoop(ListNode **pHead){if(*pHead == NULL)return;ListNode *tmp = *pHead;//ListNode *pCur = tmp->next->next;while(tmp->next){tmp = tmp->next;}tmp->next = *pHead;//tmp->next = pCur;}//判断链表是否存在环bool isLoop(ListNode *pHead){//链表是否为空if(pHead == NULL)return false;ListNode *slow = pHead;//一次只走一步的指针ListNode *fast = pHead;//一次走两步的指针while(fast->next)//fast指针是否为空{slow = slow->next;//走一步fast = fast->next;if(fast->next){fast = fast->next;}else{return false;}if(slow == fast)//如果两个指针相等,返回true{return true;}}return false;}//链表中环的长度int lenLoop(ListNode *pHead){if(pHead == NULL)return 0;ListNode *slow = pHead;ListNode *fast = pHead;while(fast->next){slow = slow->next;fast = fast->next;if(fast->next){fast = fast->next;}else{return 0;}if(slow == fast){break;}}int len = 1;while(slow->next != fast){len++;slow = slow->next;}return len;}//带环链表中的链接点,如果不存在环则返回空指针ListNode * getJoin(ListNode *pHead){if(pHead == NULL)return NULL;ListNode *slow = pHead;ListNode *fast = pHead;while(fast->next){slow = slow->next;fast = fast->next;if(fast->next){fast = fast->next;}else{return NULL;}if(fast == slow){while(slow != pHead){slow = slow->next;pHead = pHead->next;}return slow;}}return NULL;}//返回带环链表的长度,如果不存在环,则返回链表的长度int getLenLoopList(ListNode *pHead){if(pHead == NULL)return 0;ListNode *slow = pHead;ListNode *fast = pHead;int len = 1;while(fast->next){slow = slow->next;len++;fast = fast->next;if(fast->next){fast = fast->next;}else{return (len - 1) * 2;}if(slow == fast){int len1 = 1;int len2 = 0;ListNode *pos = slow;while(slow->next != fast){slow = slow->next;len1++;}while(pos != pHead){pos = pos->next;pHead = pHead->next;len2++;}return len1 + len2;}}return len * 2 - 1;}int main(void){ListNode *pHead = NULL;for(int i = 1; i < 2; ++i){appendTail(&pHead,i);}createLoop(&pHead);system("pause");return 0;}
0 0