赞
踩
就如数字6一样的单链表结构,如何检测是否有6下部的○呢,并且求交叉点位置
使用快慢指针(一个一次走2步,一个走1步),若快慢指针第一次相遇,则有环
慢指针路程
s
=
a
+
b
s = a+b
s=a+b
快指针路程
2
s
=
a
+
b
+
n
∗
R
2s = a+b+n*R
2s=a+b+n∗R
s
=
n
∗
R
s = n*R
s=n∗R
链表的长度
L
=
a
+
b
+
c
=
n
∗
R
+
c
L = a+b+c = n*R+c
L=a+b+c=n∗R+c
又
L
=
a
+
R
L = a + R
L=a+R
则
n
∗
R
+
c
=
a
+
R
⇒
(
n
−
1
)
∗
R
+
c
=
a
n*R+c = a+R \Rightarrow (n-1)*R+c = a
n∗R+c=a+R⇒(n−1)∗R+c=a
意味着从head
开始走到入口
a
a
a 步 == 从第一次相遇点走
n
−
1
n-1
n−1 圈 + 再走
c
c
c 步
由上可以使快慢指针第一次到达相遇点时,使慢指针回到head,快指针仍在相遇点,然后两人步伐一致,最后会在入口相见。
完整代码见:https://github.com/hitskyer/course/tree/master/dataAlgorithm/chenmingming/linkedList
bool SingleList::hasLoop() { bool loop = false; ListNode fast = m_pHead, slow = m_pHead; ListNode posMeet = m_pHead, ringEntrance = m_pHead;//环的可能的入口应初始化成head if(m_pHead == NULL) { loop = false; std::cout << "list has no loop!" << std::endl; } else { while(fast && fast->pNext) { fast = fast->pNext->pNext; slow = slow->pNext; if(fast == slow) { loop = true; posMeet = fast; //第一次相遇的地方 break; } } slow = m_pHead; //接着让慢指针回到表头(这里是关键),继续一起同步前行,第二次相遇的地方为环的入口 while(slow != fast) { slow = slow->pNext; fast = fast->pNext; if(fast == slow) ringEntrance = fast; } size_t lenOf_headToEntrance = howManyNode(m_pHead,ringEntrance); size_t ringLen_1 = howManyNode(ringEntrance->pNext, ringEntrance); std::cout << "len of head to ring entrance is " << lenOf_headToEntrance << std::endl; std::cout << "entrance Node is " << ringEntrance->data << std::endl; std::cout << "len of ring is " << ringLen_1 + 1 << std::endl; std::cout << "len of List is " << lenOf_headToEntrance + ringLen_1 + 1 << std::endl; } return loop; } size_t SingleList::howManyNode(ListNode ps, ListNode pe) //计算两个指针之间有多少个节点(不包含第二个参数处的节点) { size_t count = 0; while(ps != pe) { ps = ps->pNext; ++count; } return count; }
// // Created by mingm on 2019/3/24. //检查单链表中是否存在环,求环的长度,链表长度,及环的入口 #include <iostream> #include <time.h> #include <cstdlib> #include "./homework/singleList.cpp" using namespace std; int main() { srand((unsigned)time(NULL)); //用时间随机数种子 size_t len = 10; //测试链表最大长度 for(size_t j = 1; j < len; ++j) { SingleList intList; for(size_t i = 0; i < j; ++i) { intList.AddTail(rand()%100); //添加随机数到链表 } cout << "no loop list: " << endl; intList.PrintList(); //排序前链表打印 size_t n = rand()%(intList.GetLength()); //0-链表减1的随机数 ListNode randNode = intList.GetHeadNode(); for(size_t i = 0; i != n; ++i) { randNode = randNode->pNext; //链表的一个随机节点 } ListNode originTail = intList.GetTailNode(); originTail->pNext = randNode; //尾节点接入链表中的随机位置形成环 intList.hasLoop(); //调用环检测函数 originTail->pNext = NULL; //断开环,让链表能够按照单链表析构函数析构!!!!!!! std::cout << "getListLength() is " << intList.GetLength() << std::endl; std::cout << "-----------------------------------------" << std::endl; } return 0; }
从链表长度1开始测试到9,测试结果均正确!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。