- 判断单链表是否带环,并求得相遇点
思路:快慢指针问题,(前面已经讲过快慢指针原理,在这里不再详细描述)
当快指针比慢指针多走一步,在某个环内一定会相遇在某一点;反过来则有:当两个快慢指针在某一点相遇,这个链表一定是带环的链表,反之不带环(具体过程如图)
具体代码:
//链表是否带环(并返回相遇点)
SListNode* SListIsCircle(SListNode* list)
{
assert(list);
SListNode* fast = list;
SListNode* slow = list;
while (fast&&fast->_next!=NULL)
{
fast = fast->_next->_next;
slow = slow->_next;
if (slow == fast)
{
return slow;
}
}
return NULL;
}
2.环的长度
思路:环的长度可由计数器来完成,我们已经知道环内的相遇点,故而可以从相遇点开始遍历,同时记录所遍历的节点数,当回到相遇点时,记录的节点数就是环的长度
具体代码:
//求环的长度
int SListCircleLenth(SListNode* list, SListNode* meet)
{
assert(list);
SListNode* cur = meet;
size_t count = 1;
while (cur->_next != meet)
{
cur = cur->_next;
count++;
}
return count;
}
- 求环的入口点
思路:一个结论:链表的头到入口点的距离恰好是相遇点到入口点的距离(证明如下图)
具体代码:
//求环的入口点
SListNode* SListNodeEntryNode(SListNode* list, SListNode* meet)
{
assert(list);
assert(meet);
SListNode* pHead = list;
SListNode* cur = meet;
while (pHead != cur)
{
pHead = pHead->_next;
cur = cur->_next;
}
return pHead;
}