给定一个单链表,只给出头结点指针pHead: (1)如何判断链表中是否存在环。 (2)如何知道环的长度。 (3)如何找出环的连接点。 (4)带环链表的长度。 问题一,我们设置两个指针slow和fast,slow指针每次只走一步,fast指针每次走两步,如果fast指针可以追赶上slow指针,也就是说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指针第一次相遇时,slow指针走过的长度为S,那么fast指针所走过的长度为2S,我们假设从头指针到连接点的距离为lenA,从连接点到碰撞点p的距离为lenP,假设环的长度为R,那么: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; }
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; }
单链表中是否有环(长度和连接点)
最新推荐文章于 2021-05-21 16:14:30 发布