可以简单的通过一个“快指针”和一个“慢指针”来实现:
#include <stdio.h>
#include <stdlib.h>
#define bool int
#define false 0
#define true 1
struct lis
{
int MyData;
struct lis * MyNext;
};
//判断链表是否含有环
bool HasLoopOrNot(struct lis * ls)
{
bool bResult = false;
struct lis *fast = ls;
struct lis *slow = ls;
while ((fast != NULL) && (fast->MyNext != NULL) && (fast->MyNext->MyNext != NULL))
{
fast = fast->MyNext->MyNext;
slow = slow->MyNext;
if (fast==slow)
{
return true;
}
}
return false;
}
//如果存在环,则返回环的入口节点
struct lis * EnterNode(struct lis *ls)
{
struct lis *fast = ls;
struct lis *slow = ls;
while ((fast!=NULL)&&(fast->MyNext!=NULL)&&(fast->MyNext->MyNext))
{
fast = fast->MyNext->MyNext;
slow = slow->MyNext;
if (fast==slow)//相遇,存在环
{
break;
}
}
//算法思想:
/******************
当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1 <= n)。
假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
2s = s + nr
s = nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r + r = (n - 1)r + L - a
a = (n - 1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n - 1)循环内环 + 相遇点到环入口点,
于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
******************/
//fast停在第一个相遇点
slow = ls;//slow重新指向链表的第一个节点
while (slow!=fast)
{
fast = fast->MyNext;
slow = slow->MyNext;
}
return slow;//或者return fast;
}
int main()
{
struct lis *node1 = calloc(sizeof(struct lis), 1);
struct lis *node2 = calloc(sizeof(struct lis), 1);
struct lis *node3 = calloc(sizeof(struct lis), 1);
struct lis *node4 = calloc(sizeof(struct lis), 1);
struct lis *node5 = calloc(sizeof(struct lis), 1);
struct lis *node6 = calloc(sizeof(struct lis), 1);
struct lis *node7 = calloc(sizeof(struct lis), 1);
struct lis *node8 = calloc(sizeof(struct lis), 1);
struct lis *node9 = calloc(sizeof(struct lis), 1);
node1->MyNext = node2;
node2->MyNext = node3;
node3->MyNext = node4;
node4->MyNext = node5;
node5->MyNext = node6;
node6->MyNext = node7;
node7->MyNext = node8;
node8->MyNext = node9;
node9->MyNext = node4;//含有环
//node9->MyNext = NULL;//不含环
node1->MyData = 2001;
node2->MyData = 2002;
node3->MyData = 2003;
node4->MyData = 2004;
node5->MyData = 2005;
node6->MyData = 2006;
node7->MyData = 2007;
node8->MyData = 2008;
node9->MyData = 2009;
bool br = HasLoopOrNot(node1);
if (br)
{
printf("含有环\n");
}
else
printf("not含有环\n");
printf("---------------------------------------\n");
struct lis * enter = EnterNode(node1);
printf("入口节点的值是:%d\n", enter->MyData);
return 0;
}