思路:定义一个快指针每次走两步,慢指针每次走一步,如果有环则快慢指针会相遇。
用一个指针记录交点,求交点的下一节点 至 交点和头指针的下一节点 至 交点两条链表的相交节点即为环的入口。
Node *ringstart_node(Node *head)
{
//定义一个快指针走两步和一个慢指针走一步
Node *quick = head->next;
Node *slow = head->next;
// Cross指交点 初始化为NULL
Node *Cross = NULL;
//快指针刚好指向最后一位时时说明链表长度为奇数 指向空时长度为偶数
while (quick != NULL && quick->next != NULL)
{
quick = quick->next->next;
slow = slow->next;
//当快慢指针相遇时 用Cross记录交点
if (slow == quick)
{
Cross = quick;
break;
}
}
printf("cross = %d\n", Cross->value);
//没有交点直接返回
if (Cross == NULL)
{
return NULL;
}
//定义两个指针分别指向起点 终点为Cross
Node *start1 = head->next;
Node *start2 = Cross->next;
int n1 = getlen(head, Cross);
int n2 = getlen(Cross, Cross);
printf("n1 = %d n2=%d\n", n1, n2);
// 计算起点至相交点 相交点至相交点距离 n记录差值
int n;
// 判断找出长的链表
if (n1 >= n2)
{
start1 = head->next;
start2 = Cross->next;
n = n1 - n2;
}
else if (n1 < n2)
{
start1 = Cross->next;
start2 = head->next;
n = n2 - n1;
}
// 长的链表先移动
for (int i = 0; i < n; i++)
{
start1 = start1->next;
}
//两条链表一起移动 节点相等即为环的入口
while (start1->next != Cross)
{
if (start1 == start2)
{
printf("环的起点为:%d\n", start1->value);
return start1;
}
start1 = start1->next;
start2 = start2->next;
}
}
int getlen(Node *head, Node *Cross)
{
int n = 0;
Node *node = head->next;
while (node != Cross)
{
n++;
node = node->next;
}
return n;
}