笔试,面试,C/C++,判断单链表是否带环?若带环,求环长度,求环入口点(两种方法)

来源:互联网 发布:无法备案的域名 编辑:程序博客网 时间:2024/06/02 00:18



SListNode* IsRing(SListNode *&pHead) //判断链表是否有环,求相聚点{ //判空、有、没有 //思路:两个指针从头开始一快(2步)一慢(1步),若最后可以相聚,则链表有环 if (pHead) {  SListNode *fast = pHead;  SListNode *slow = pHead;  while (fast&&fast->next)  {   fast = fast->next->next;   slow = slow->next;   if (slow == fast)    return fast;  }  return NULL; } return NULL;}int RingLength(SListNode *&pHead)//求链表环长度{ //先判断链表有环 //思路:从IsRing得到的点开始走一圈环,记录结点个数 if (pHead)//判空 {  SListNode* point = IsRing(pHead);  if (point != NULL)//无环情况  {   int count = 1;   SListNode *tmp = point->next;   while (tmp != point)   {    tmp = tmp->next;    count++;   }   return count;  } } return 0;}SListNode* RingEntry(SListNode *&pHead)//找环入口{ //判是否为空、有环 //思路:判断有环,找到快慢指针的相聚点,然后一个指针从聚点开始,一个从头开始,每次一步,相遇点就为入口节点 if (pHead)//判空 {  SListNode *tmp = IsRing(pHead);  if (tmp)//判有环  {   SListNode *cur = pHead;   while (cur!=tmp)   {    cur = cur->next;    tmp = tmp->next;   }   return cur;  }  return NULL; } return NULL;}int _LengthNode(SListNode*& pHead)//RingEntry_Point内部函数,求链表长度{ if (pHead) {  SListNode *tmp = pHead;  int count = 0;  while (tmp)  {   count++;   tmp = tmp->next;  }  return count; } return 0;}SListNode* RingEntry_Point(SListNode *&pHead)//找环入口_链表相交法{ //判是否为空、有环 //思路:在快慢指针相聚点截断,将环链表变为两个相交链表,因为相交链表尾部重合呈Y字型, //     求两个链表长度之差K,再令一个指针从长链表开始先走K步,令另一个指针从短链表头开始, //     两链表一起走,相遇点就为入口点 // //经过调试发现 还必须在返回之前将链表复原,不然会出现丢失链表结点的情况,应对函数进行修改 if (pHead)//判空 {  SListNode *tmp = IsRing(pHead);  if (tmp)//判有环  {   SListNode *cur = pHead;   SListNode *NewNode = tmp->next;   tmp->next = NULL;   int c1 = _LengthNode(cur);   int c2 = _LengthNode(NewNode);   int minus = _LengthNode(cur) - _LengthNode(NewNode);   if (minus > 0)   {    while (minus--)    {     cur = cur->next;    }   }   else   {    int tmp = -minus;    while (tmp--)    {     NewNode = NewNode->next;    }   }   while (NewNode!=cur)   {    NewNode = NewNode->next;    cur = cur->next;   }   return cur;  }  return NULL; } return NULL;}void Test9()  //IsRing/RingLength/RingEntry_1/RingEntry_2{ printf("//Test9() IsRing/RingLength/RingEntry/RingEntry_Point \n"); SListNode *LL = NULL; PushBack(LL, 1); PushBack(LL, 2); PushBack(LL, 3); PushBack(LL, 4); PushBack(LL, 5); PrintNode(LL); //printf("%d\n", _LengthNode(LL)); printf("\nRingLength = %d\n", RingLength(LL));//不是环 SListNode*tmp = RingEntry(LL); PrintNode(tmp); tmp = RingEntry_Point(LL); PrintNode(tmp); Find(LL, 5)->next = Find(LL, 5);//尾结点呈环 printf("\nRingLength = %d\n", RingLength(LL)); printf("RingEntry = %d\n", RingEntry(LL)->data); printf("RingEntry_Point = %d\n", RingEntry_Point(LL)->data); Find(LL, 5)->next = Find(LL, 3);//中间结点开始呈环 printf("\nRingLength = %d\n", RingLength(LL)); printf("RingEntry = %d\n", RingEntry(LL)->data); printf("RingEntry_Point = %d\n", RingEntry_Point(LL)->data);//由于函数实现时没有将断开的环闭合,导致丢失数据 //函数RingEntry_Point在此处将原链表破坏丢失元素5 //Find(LL, 5)->next = Find(LL, 1);//整个链表为环链表已不存在元素为5的结点 出现错误 Find(LL, 4)->next = Find(LL, 1);//整个链表为环 printf("\nRingLength = %d\n", RingLength(LL)); printf("RingEntry = %d\n", RingEntry(LL)->data); printf("RingEntry_Point = %d\n", RingEntry_Point(LL)->data);}


wKioL1aKnBjSFkciAAAolbGCv8c251.png

 对函数SListNode* RingEntry_Point(SListNode *&pHead)进行修改后

SListNode* RingEntry_Point(SListNode *&pHead)//找环入口_链表相交法{ //判是否为空、有环 //思路:在快慢指针相聚点截断,将环链表变为两个相交链表,因为相交链表尾部重合呈Y字型, //     求两个链表长度之差K,再令一个指针从长链表开始先走K步,令另一个指针从短链表头开始, //     两链表一起走,相遇点就为入口点 // //经过调试发现 还必须在返回之前将链表复原,不然会出现丢失链表结点的情况,应对函数进行修改 //在实现函数功能之后将环复原 // if (pHead)//判空 {  SListNode *tmp = IsRing(pHead);  if (tmp)//判有环  {   SListNode *cur = pHead;   SListNode *NewNode = tmp->next;   SListNode*tmp_fail = tmp;//将截断处保存   SListNode*tmp_head = NewNode;   tmp->next = NULL;//将环从tmp处截断   int c1 = _LengthNode(cur);   int c2 = _LengthNode(NewNode);   int minus = _LengthNode(cur) - _LengthNode(NewNode);   if (minus > 0)   {    while (minus--)    {     cur = cur->next;    }   }   else   {    int tmp = -minus;    while (tmp--)    {     NewNode = NewNode->next;    }   }   while (NewNode!=cur)   {    NewNode = NewNode->next;    cur = cur->next;   }   tmp_fail->next = tmp_head;//将原环修复   return cur;  }  return NULL; } return NULL;}


wKioL1afceOi4DZsAAEOCRil0Mo887.jpg

0 0