求带环链表的入口的多种解法

来源:互联网 发布:网站源码下载 编辑:程序博客网 时间:2024/05/28 04:55

方法1:

公式推导:定义两个指针,一个快指针,一个慢指针。两个指针一起走,快指针每次走两步,慢指针每次走一步(相当于速度不一样)。如果有环,那么它们就一定会相遇,当他们相遇时,走的次数是一样的(相当于时间),路程不一样。且,快指针的路程是慢指针的路程的2倍。这就的到了图中的第一个公式。将第一个公式进行一系列的化简,得出最后一个公式。

通过最后一个公式我们可以知道,如果有两个指针同时走,一个从相遇点出发(相当于少走了y),一个从链的起点出发,那么,它们一定会在环的入口点相遇的。


pNode GetCircleEntryNode(pNode meet, pList plist)//方法1{pNode first = meet;//从相遇点出发pNode second = plist;//从起点出发if ((plist == NULL) || (meet==NULL))//相遇点为NULL,代表没有环{return NULL;}while (first!=second){first = first->next;second = second->next;}return first;}


方法2:

定义两个指针,第一个指针先走环的长度步,然后两个指针一起走,当他们相遇的时候停下来,相遇点便是入口点。

 

 

pNode GetCircleEntryNode(int len,pList plist)//方法2{pNode first = plist;pNode second = plist;if ((plist == NULL)||(len==0))//环的长度为0,说明没有环{return NULL;}while (len-->0)//第一个指针先走环的长度步{first = first->next;}while (first!=second){first = first->next;second = second->next;}return first;}

方法3:

从相遇点断开,就相当于有交点的两条链。将两条链的长度len1,len2分别求出来,用k来表示长度之差,哪个长一点,哪个就先走K步,K步走完后,长的链剩下的长度和短的链一样长,那么,它们到交点(环的入口)距离一样远,现在同时走,相遇点便是入口点。


pNode GetCircleEntryNode(pNode meet, pList plist)//方法3{pNode first = meet;pNode second = plist;pNode cur = meet;//cur指针用于记住相遇点的位置,方便后边从此断开int len1 = 0;int len2 = 0;if ((plist == NULL) || (meet == NULL)){return 0;}first = first->next;//让first指针指向相遇点的下一个位置cur->next = NULL;//将链表从相遇点断开,链表变成两条有交点的链cur = first;//cur记住L1的起始位置,方便下一次便利的时候可以找到头while (first!=NULL)//遍历L1,求出其长度len1{++len1;first = first->next;}while (second != NULL)//遍历L2,求出其长度了len2{++len2;second = second->next;}first = cur;//让first指针指向链L1的起点second = plist;//让second指针指向链L1的起点if (len1 > len2)//比较两条链的长度,两条链哪条长哪条先走{int k = len1 - len2;while (k-- > 0){first = first->next;}while (first != second)//让两个指针同时往后走走,指向同一点及交叉点时停下{first = first->next;second = second->next;if (first == second){return first;}}}else{int k = len2 - len1;while (k-- > 0){second = second->next;}while (first != second){first = first->next;second = second->next;if (first == second){return first;}}}}

下边是相关函数的实现和测试代码

头文件和函数声明LinkNode.h部分

#ifndef __LINKLIST_H__ #define __LINKLIST_H__ #include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>typedef int DataType; typedef struct Node { DataType data; struct Node* next; }Node, *pNode, *pList;void InitLinkList(pList* pplist); //初始化void PushFront(pList*pplist, DataType x);//前加 void Display(pList pl); //打印void DestroyList(pList* pplist);//销毁  pNode Find(pList pl, DataType x); //查找函数 pNode CheckCycle(pList plist);//判断是否有环int GetCircleLength(pNode meet);//求环的长度pNode GetCircleEntryNode(pNode meet, pList plist);//求环的入口//pNode GetCircleEntryNode(int len,pList plist)
#endif //__LINKLIST_H__

各个函数的具体实现LinkNode.c部分

#include "LinkNode.h"void InitLinkList(pList* pplist)//初始化{assert(pplist != NULL);*pplist = NULL;}void PushFront(pList*pplist, DataType x)//前加{assert(pplist != NULL);pNode node = malloc(sizeof(Node));if (node == NULL){perror("malloc");exit(EXIT_FAILURE);}node->data = x;node->next = NULL;node->next = *pplist;*pplist = node;} void Display(pList pl)//打印{if (pl == NULL){return;}while (pl != NULL){printf("%d-->", pl->data);pl = pl->next;}printf("\n");}void DestroyList(pList* pplist)//销毁 {assert(pplist != NULL);while (*pplist != NULL){pNode tmp = (*pplist)->next;free(*pplist);(*pplist)->next = NULL;*pplist = tmp;}} pNode Find(pList pl, DataType x) //查找函数{pNode head = pl;while (head->data != x){head = head->next;}if (head->data == x){return head;}else{return NULL;}} //判断是否有环 pNode CheckCycle(pList plist){pNode fast = plist;pNode slow = plist;if (plist == NULL){return NULL;}while ((fast != NULL) && (fast->next != NULL)) {fast = fast->next->next;slow = slow->next;if (fast == slow){return fast;}}return NULL;} //求环的长度int GetCircleLength(pNode meet){pNode Meet = NULL;int count = 0;if (meet == NULL){return count;}Meet = CheckCycle(meet);meet = Meet;Meet = Meet->next;count++;while (Meet != meet){count++;Meet = Meet->next;}return count;}//求环的入口 //pNode GetCircleEntryNode(pNode meet, pList plist)//方法1//{//pNode first = meet;//从相遇点出发//pNode second = plist;//从起点出发//if ((plist == NULL) || (meet==NULL))//相遇点为NULL,代表没有环//{//return NULL;//}//while (first!=second)//{//first = first->next;//second = second->next;//}//return first;//}////pNode GetCircleEntryNode(int len,pList plist)//方法2//{//pNode first = plist;//pNode second = plist;//if ((plist == NULL)||(len==0))//环的长度为0,说明没有环//{//return NULL;//}//while (len-->0)//第一个指针先走环的长度步//{//first = first->next;//}//while (first!=second)//{//first = first->next;//second = second->next;//}//return first;//}pNode GetCircleEntryNode(pNode meet, pList plist)//方法3{pNode first = meet;pNode second = plist;pNode cur = meet;//cur指针用于记住相遇点的位置,方便后边从此断开int len1 = 0;int len2 = 0;if ((plist == NULL) || (meet == NULL)){return 0;}first = first->next;//让first指针指向相遇点的下一个位置cur->next = NULL;//将链表从相遇点断开,链表变成两条有交点的链cur = first;//cur记住L1的起始位置,方便下一次便利的时候可以找到头while (first!=NULL)//遍历L1,求出其长度len1{++len1;first = first->next;}while (second != NULL)//遍历L2,求出其长度了len2{++len2;second = second->next;}first = cur;//让first指针指向链L1的起点second = plist;//让second指针指向链L1的起点if (len1 > len2)//比较两条链的长度,两条链哪条长哪条先走{int k = len1 - len2;while (k-- > 0){first = first->next;}while (first != second)//让两个指针同时往后走走,指向同一点及交叉点时停下{first = first->next;second = second->next;if (first == second){return first;}}}else{int k = len2 - len1;while (k-- > 0){second = second->next;}while (first != second){first = first->next;second = second->next;if (first == second){return first;}}}} 

测试函数test.c部分

#include "LinkNode.h" void test(){pList list;int len = 0;pNode meet = NULL;pNode ret1 = NULL;pNode ret2 = NULL;pNode ret3 = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);PushFront(&list, 5);PushFront(&list, 6);PushFront(&list, 7);PushFront(&list, 8);PushFront(&list, 9);Find(list, 1)->next = Find(list, 5);meet = CheckCycle(list);len = GetCircleLength(meet);//验证方法1//ret1 = GetCircleEntryNode(meet,list);/*if (ret1 == NULL){printf("NOCYCLE\n");}else{printf("the entry is:%d\n",ret1->data);}*///验证方法2ret2 = GetCircleEntryNode(len, list);if (ret2 == NULL){printf("NOCYCLE\n");}else{printf("the entry is:%d\n", ret2->data);}//验证方法3/*ret3 = GetCircleEntryNode(meet, list);if (ret3 == NULL){printf("NOCYCLE\n");}else{printf("the entry is:%d\n", ret3->data);}*/} int main(){ test();  return 0;}
PS:想要验证哪种方法就就哪种方法的函数和测试代码放开就OK了。


阅读全文
1 0
原创粉丝点击