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);
}
对函数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;
}