判断单链表是否带环,可以先定义两个指向链表首节点的快慢指针,快指针每次沿着链表向后走两次,慢指针向后走一次,若快慢指针相遇说明链表带环。
环的长度:在快慢指针第一次相遇时记录相遇点,让慢指针继续走,再次经过相遇点时经过的长度便是环的长度。
入口点:假设从链表的头到环的入口点长度为L,从入口点到第一次相遇点的长度为d,从第一次相遇点到入口点的长度为x,根据快指针走过的长度是慢指针的两倍可以得到 2*(L+d)=L+n(x+d)+d,其中n为快指针经过环的圈数(n>=0),化简得到,L=x+(n-1)(x+d),其中x+d为环的长度。也就是说,定义一个指针从第一次相遇点开始走,另一个指针从链表头开始走,后者走到环的入口时,前者刚好也走到环的入口(有可能已经经过好几次)。根据这个关系,即可求出环的入口点。
typedef int DataType;
typedef struct SListNode
{
struct SListNode* _next;
DataType _data;
}SListNode;
SListNode* SListIsCycle(SListNode* list)
{
assert(list);
SListNode* fast = list;
SListNode* slow = list;
SListNode* cur1 = list;
SListNode* cur2;
SListNode* next;
int count = 1;
while (fast->_next!=NULL)
{
slow = slow->_next;
fast = fast->_next;
fast = fast->_next;
if (slow == fast)
{
cur2 = fast;
next = cur2->_next;
while (next != cur2)
{
next = next->_next;
count++;
}
printf("环的长度为%d\n", count);
break;
}
}
if (fast->_next == NULL)
{
return NULL;
}
while (cur1 != fast)
{
cur1 = cur1->_next;
fast = fast->_next;
}
return cur1;
}