问题描述:
判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复 杂度&空间复杂度。
1、判断单链表是否带环:
实现思路:设置两个快慢指针分别指向链表的头节点,快指针一次走两步,慢指针一次走一步,如果两个相遇了,则单链表带环,如果快指针走到NULL节点,则链表不带环;
代码实现如下:
pSListNode IsCircleList(pSListNode pHead)
{
pSListNode fast = pHead; //快指针
pSListNode slow = pHead; //慢指针
if (pHead == NULL)
{
return NULL;
}
while (fast&&fast->_next)
{
slow = slow->_next;
fast = fast->_next->_next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
2、如果单链表带环,求环的长度:
实现思路:在判断单链表是否带环的问题中,我们找到了单环单链表的相遇结点,用于个指针从单链表的相遇结点开始走,并且设置一个计数器,每走一步,计数器加一,直到该指针再次遇到相遇点,则返回计数器的数;
实现代码如下:
int CircleListLength(pSListNode pos)
{
pSListNode fast = pos;
pSListNode slow = pos;
int count = 0;
while (1)
{
slow = slow->_next;
fast = fast->_next->_next;
count++;
if (fast == slow)
break;
}
return count;
}
3、求带环长度的入口点:
实现思路:
求环的入口点
设环的长度为:C
从链表头结点到入口节点的长度为:L
入口节点到相遇节点的长度为:X
快指针在环中走的圈数:n
快指针走的步数是:L+nC+X
慢指针走的步数是:L+X
根据快指针走的步数是慢指针的两倍可得关系:L+nC+X = 2(L+X) 化简后可得:nC = L+X
结论:从链表头结点到入口节点的长度 = 相遇节点到入口节点的长度
具体代码实现如下:
pSListNode FindCircleEnter(pSListNode pHead, pSListNode pos)
{
pSListNode cur = pHead;
pSListNode tmp = pos;
assert(pos);
if (pHead == NULL)
return NULL;
while (cur != tmp)
{
cur = cur->_next;
tmp = tmp->_next;
}
return cur;
}
单链表的问题,同样也可以转换成两个单链表相交的问题,将单环单链表从相遇点断开,然后求其长度,长的先走。具体实现详见:判断两个不带环的链表是否相交,若相交,求交点