通俗易懂说单链表(2)链表/环长度、有环,环入口
1. 单链表长度
//计算单链表长度
int lengthNode(Node *node)
{
if (NULL == node)
{
cout << "error" << endl;
return 0;
}
int iLen = 0;
Node *pTmp = node;
while (pTmp->next) //从头到尾遍历链表,计数器依次累加
{
pTmp = pTmp->next;
iLen++;
}
return iLen;
}
2. 单链表是否有环?
2.1 思想
设置两个指针,都指向头结点,一个走的快,一个走的慢,
如果有环,那么若干步以后,快指针总会超过慢的指针一圈;
如果没有,那么若干步以后,快指针指向NULL。
2.2 代码实现
//单链表定义
typedef struct node {
int val;
struct node *next;
}Node,*pNode;
//判断单链表是否有环
bool isLoop(pNode pHead)
{
//省略判断pHead有效
//定义两个临时变量 快慢指针
pNode fast = pHead;
pNode slow = pHead;
//如果无环,则fast先走到终点
//当链表长度为奇数时,fast->Next为空
//当链表长度为偶数时,fast为空
while( fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
//如果有环,则fast会超过slow一圈
if(fast == slow)
{
break;
}
}
if(fast == NULL || fast->next == NULL )
{
return false;
}
else
{
return true;
}
}
3. 单链表环入口
3.1 思想
第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,
因此,慢,快指针分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。
3.1.1 证明
在环上相遇后,假设起始点到环入口长度为 len1,环入口到相遇点位置为 len2,环长度为R,则:
慢指针: S = len1 + len2
快指针: 2S = len1 + R + len2
所以推到出: len1 = R - len2
即证明了第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离。
3.2 代码实现
Node* findLoopEntrance(pNode pHead)
{
pNode fast = pHead;
pNode slow = pHead;
while( fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
//如果有环,则fast会超过slow一圈
if(fast == slow)
{
break;
}
}
if(fast == NULL || fast->next == NULL)
return NULL;
slow = pHead; //慢指针重新指向头节点
while(slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
4. 单链表环长度
4.1 思想
快慢指针第一次相遇(超一圈)时开始计数,计数器累加,第二次相遇时停止计数
第二次相遇的时候快指针比慢指针正好又多走了一圈,也就是多走的距离等于环长
4.2 代码实现
//计算单链表环的长度
int loopLength(pNode pHead)
{
//首先通过上面的借口判断,链表是否有环
if(isLoop(pHead) == false)
{
return 0; //没有环,则直接返回
}
pNode fast = pHead;
pNode slow = pHead;
int length = 0; //环的长度
bool begin = false; //第一次相遇的 flag
bool agian = false; //第二次相遇的 flag
while( fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
//超两圈后停止计数,挑出循环
if(fast == slow && agian == true)
{
break;
}
//超一圈后开始计数
if(fast == slow && agian == false)
{
begin = true;
agian = true;
}
//计数 +1
if(begin == true)
{
++length;
}
}
return length;
}
5. 参考
http://www.cnblogs.com/xudong-bupt/p/3667729.html