1、判断链表是否带环?
链表是否带环,可以采用快慢指针法,用两个指针指向链表的头结点,一个指针一次向后走一个位置,另一个指针向后走两个位置,这样如果两个指针如果相遇,这样就能说该链表带环,如果当快指针或者快指针的next为NULL时,还没有相遇。哪么就说明该链表不带环。
我实现时,用一个pair模板去实现,这样为了方便后面两个问题的解决。
代码实现:
#include<assert.h>
struct ListNode{
int val;
ListNode* next;
ListNode(int _val)
:val(_val)
, next(NULL)
{}
};
pair<ListNode*, bool> IsExitsLoop(ListNode* Head) //求环
{
assert(Head != NULL);
ListNode* slow = Head; //快指针
ListNode* fast = Head; //慢指针
while (slow != NULL && slow->next != NULL)
{
slow = slow->next->next;
fast = fast->next;
if (slow == fast)
return make_pair(fast, true);
}
return make_pair(slow, false);
}
2、若带环则求环的长度?
当链表带环时,我们可以发现从两个快慢指针相遇的结点走一圈,就能求出该环的长度。
代码实现:
int length(pair<ListNode*, bool> l)
{
if (l.second == false)
exit(1);
int length = 0;
ListNode* node = l.first;
do{
length++;
node = node->next;
} while (node != l.first);
return length;
}
3、若带环则求环的入口点?
当带环时,要求带环的入口点。这个我们可以利用数学知识去计算。
假设链表总长为L,头节点到入口点的距离为a,入口点到快慢指针交点距离为x,环的长度为R,现在假设慢指针走了S步与快指针相遇,那么慢指针走的路程为S=a+x;快指针走的路程为2S = a+x+nR;那么a+x=nR;
a = nR-x;
那么我们可以知道快慢指针相交节点之后,再另一个指针去指向头结点,我们让这个指针与在相交节点的指针去共同向后走,直到两个节点相交,这个时候这个的节点就是我们所要求的的入口节点。
代码实现:
ListNode* FindLoopPort(ListNode* head)
{
ListNode* ptr = head;
ListNode* end = NULL;
if (IsExitsLoop(head).second)
end = IsExitsLoop(head).first;
while (ptr != end)
{
ptr = ptr->next;
end = end->next;
}
if (ptr == end)
return ptr;
else
return NULL;
}