给定一个单链表,只给出头结点指针pHead:
(1)如何判断链表中是否存在环。
(2)如何知道环的长度。
(3)如何找出环的连接点。
(4)带环链表的长度。
问题一,我们设置两个指针slow和fast,slow指针每次只走一步,fast指针每次走两步,如果fast指针可以追赶上slow指针,也就是说fast指针和slow指针相等。那么我们就说链表中存在环,否则,当fast指针为空时,我们说链表中不存在环。 bool isLoop(ListNode *pHead)
{
//链表是否为空
if(pHead == NULL)
return false;
ListNode *slow = pHead;//一次只走一步的指针
ListNode *fast = pHead;//一次走两步的指针
while(fast && fast->next)
{
slow = slow->next;//走一步
fast = fast->next->next;
if(slow == fast)//如果两个指针相等,返回true
{
return true;
}
}
return false;
}
问题二:在问题一的基础上,我们找到slow指针和fast指针相遇点即碰撞点。我们从碰撞点开始,每次走一步,直到再次回到出发点,所走过的步数即为环的长度。当链表中不存在环时,返回环的长度为零。int lenLoop(ListNode *pHead)
{
if(pHead == NULL)
return 0;
ListNode *slow = pHead;
ListNode *fast = pHead;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
break;
}
}
//当链表中不存在环时返回长度为零
if((fast == NULL) || (fast->next == NULL))
return 0;
int len = 1;
while(slow->next != fast)
{
len++;
slow = slow->next;
}
return len;
}
问题三:我们可以根据碰撞点到连接点的距离等于头指针到连接点的距离,我们可以分别从碰撞点和头指针开始,当两个指针相遇时,相遇的位置即连接点的位置。我们可以简单的证明一下,当slow指针和fast指针第一次相遇时,slow指针走过的长度为S,那么fast指针所走过的长度为2S,我们假设从头指针到连接点的距离为lenA,从连接点到碰撞点p的距离为lenP,假设环的长度为R,那么: S = lenA + lenP; 2S = lenA + n*R + lenP; 由以上可以得到: lenA = n*R - lenP; 因此碰撞点到连接点的距离等于头指针到连接点的距离。(可能访问环多次)。//带环链表中的链接点,如果不存在环则返回空指针
ListNode * getJoin(ListNode *pHead)
{
if(pHead == NULL)
return NULL;
ListNode *slow = pHead;
ListNode *fast = pHead;
while(fast->next)
{
slow = slow->next;
fast = fast->next;
if(fast->next)
{
fast = fast->next;
}
else
{
return NULL;
}
if(fast == slow)
{
while(slow != pHead)
{
slow = slow->next;
pHead = pHead->next;
}
return slow;
}
}
return NULL;
}
问题四:我们在问题二已经求出链表中环的长度,在问题三中我们求出连接点的位置,那么链表的长度等于链表中环的长度和从头指针到连接点距离之和。返回带环链表的长度,如果不存在环,则返回链表的长度。int getLenLoopList(ListNode *pHead)
{
if(pHead == NULL)
return 0;
ListNode *slow = pHead;
ListNode *fast = pHead;
int len = 1;
while(fast->next)
{
slow = slow->next;
len++;
fast = fast->next;
if(fast->next)
{
fast = fast->next;
}
else
{
return (len - 1) * 2;
}
if(slow == fast)
{
int len1 = 1;
int len2 = 0;
ListNode *pos = slow;
while(slow->next != fast)
{
slow = slow->next;
len1++;
}
while(pos != pHead)
{
pos = pos->next;
pHead = pHead->next;
len2++;
}
return len1 + len2;
}
}
return len * 2 - 1;
}
完整版代码:#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
};
void appendTail(ListNode **pHead,int val)
{
ListNode *pNew = new ListNode;
pNew->next = NULL;
pNew->val = val;
if(*pHead == NULL)
{
*pHead = pNew;
}
else
{
ListNode *tmp = *pHead;
while(tmp->next)
{
tmp = tmp->next;
}
tmp->next = pNew;
}
}
void show(ListNode *pHead)
{
while(pHead)
{
cout<<pHead->val<<endl;
pHead = pHead->next;
}
}
//创建一个带环的链表
void createLoop(ListNode **pHead)
{
if(*pHead == NULL)
return;
ListNode *tmp = *pHead;
//ListNode *pCur = tmp->next->next;
while(tmp->next)
{
tmp = tmp->next;
}
tmp->next = *pHead;
//tmp->next = pCur;
}
//判断链表是否存在环
bool isLoop(ListNode *pHead)
{
//链表是否为空
if(pHead == NULL)
return false;
ListNode *slow = pHead;//一次只走一步的指针
ListNode *fast = pHead;//一次走两步的指针
while(fast->next)//fast指针是否为空
{
slow = slow->next;//走一步
fast = fast->next;
if(fast->next)
{
fast = fast->next;
}
else
{
return false;
}
if(slow == fast)//如果两个指针相等,返回true
{
return true;
}
}
return false;
}
//链表中环的长度
int lenLoop(ListNode *pHead)
{
if(pHead == NULL)
return 0;
ListNode *slow = pHead;
ListNode *fast = pHead;
while(fast->next)
{
slow = slow->next;
fast = fast->next;
if(fast->next)
{
fast = fast->next;
}
else
{
return 0;
}
if(slow == fast)
{
break;
}
}
int len = 1;
while(slow->next != fast)
{
len++;
slow = slow->next;
}
return len;
}
//带环链表中的链接点,如果不存在环则返回空指针
ListNode * getJoin(ListNode *pHead)
{
if(pHead == NULL)
return NULL;
ListNode *slow = pHead;
ListNode *fast = pHead;
while(fast->next)
{
slow = slow->next;
fast = fast->next;
if(fast->next)
{
fast = fast->next;
}
else
{
return NULL;
}
if(fast == slow)
{
while(slow != pHead)
{
slow = slow->next;
pHead = pHead->next;
}
return slow;
}
}
return NULL;
}
//返回带环链表的长度,如果不存在环,则返回链表的长度
int getLenLoopList(ListNode *pHead)
{
if(pHead == NULL)
return 0;
ListNode *slow = pHead;
ListNode *fast = pHead;
int len = 1;
while(fast->next)
{
slow = slow->next;
len++;
fast = fast->next;
if(fast->next)
{
fast = fast->next;
}
else
{
return (len - 1) * 2;
}
if(slow == fast)
{
int len1 = 1;
int len2 = 0;
ListNode *pos = slow;
while(slow->next != fast)
{
slow = slow->next;
len1++;
}
while(pos != pHead)
{
pos = pos->next;
pHead = pHead->next;
len2++;
}
return len1 + len2;
}
}
return len * 2 - 1;
}
int main(void)
{
ListNode *pHead = NULL;
for(int i = 1; i < 2; ++i)
{
appendTail(&pHead,i);
}
createLoop(&pHead);
system("pause");
return 0;
}