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



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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值