一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):
关于这个解法最形象的比喻就是在操场当中跑步,速度快的会把速度慢的扣圈
可以证明,p2追赶上p1的时候,p1一定还没有走完一遍环路,p2也不会跨越p1多圈才追上
我们可以从p2和p1的位置差距来证明,p2一定会赶上p1但是不会跳过p1的
因为p2每次走2步,而p1走一步,所以他们之间的差距是一步一步的缩小,4,3,2,1,0 到0的时候就重合了
根据这个方式,可以证明,p2每次走三步以上,并不总能加快检测的速度,反而有可能判别不出有环
比如,在环的周长L是偶数的时候,初始p2和p1相差奇数的时候,p2每次走三步,就永远和p1不重合,因为他们之间的差距是: 5, 3 , 1, L-1, L-3
如下代码:
bool check(const node* head)
{
if(head==NULL) return false;
node *low=head, *fast=head->next;
while(fast!=NULL && fast->next!=NULL)
{
low=low->next;
fast=fast->next->next;
if(low==fast) return true;
}
return false;
}
既然能够判断出是否是有环路,那改如何找到这个环路的入口呢?
解法如下: 当p2按照每次2步,p1每次一步的方式走,发现p2和p1重合,确定了单向链表有环路了
接下来,让p2回到链表的头部,重新走,每次步长不是走2了,而是走1,那么当p1和p2再次相遇的时候,就是环路的入口了。
这点可以证明的:
在p2和p1第一次相遇的时候,假定p1走了n步骤,环路的入口是在p步的时候经过的,那么有
p1走的路径: p+c = n; c为p1和p2相交点,距离环路入口的距离
p2走的路径: p+c+k*L = 2*N; L为环路的周长,k是整数
显然,如果从p+c点开始,p1再走n步骤的话,还可以回到p+c这个点
同时p2从头开始走的话,经过n不,也会达到p+c这点
显然在这个步骤当中p1和p2只有前p步骤走的路径不同,所以当p1和p2再次重合的时候,必然是在链表的环路入口点上。
#include <iostream>
#include <stdlib.h>
using namespace std;
class CList {
public:
int nData;
CList * pNext;
} * pRoot = NULL;
const int size = sizeof(CList) / sizeof(int);
int buffer[101*size];
bool Init(int n)
{
pRoot = (CList*)buffer;
if ( n<1 && n>98 ) return false;
CList * pTemp = NULL;
for ( int i=0; i<101; i++ ) {
pTemp = new (buffer+i*size) CList();
pTemp->nData = i;
pTemp->pNext = (CList *)(buffer + (i+1)*size);
};
pTemp->pNext = (CList *) (buffer + n*size);
return true;
}
void ClearCircle(CList * pRoot)
{
CList * p1, * p2;
p1 = p2 = pRoot;
do {
p2 = p2->pNext->pNext;
p1 = p1->pNext;
} while ( p2!=NULL && p1!=p2);
if ( p1 == p2 ) {
p2 = pRoot;
while (1) {
p2 = p2->pNext;
if ( p1->pNext == p2 ) break;
p1 = p1->pNext;
}
p1->pNext = NULL;
}
}
int main(int argc, char *argv[])
{
CList * pList = pRoot;
if (Init(21) )
{
cout << "Before clear:!" << "\r\n";
pList = pRoot;
for ( int i=0; i<104; i++)
{
cout << pList->nData << "\r\n";
pList = pList->pNext;
}
ClearCircle(pRoot);
}
cout << "After clear:" << "\r\n";
pList = pRoot;
while (pList) {
cout << pList->nData << "\r\n";
pList = pList->pNext;
}
return 0;
}
分享到:
相关推荐
**1、判断链表是否有环** **2、寻找环的入口点** **3、计算环的节点数** **4、计算(有环)链表的节点数** **5、找出环中距任意一点最远的节点** **6、判断两个无环链表是否相交** **7、寻找两个链表的相交的节点**
约瑟夫环问题,也被称为...无论是数组还是链表实现,都需要对数据结构有深入的理解,并能够根据问题特点灵活选择合适的方法。在实际应用中,我们可以根据问题规模、内存限制以及计算性能要求,来决定采用哪种实现方式。
当快慢指针相遇时,即可确定链表有环。 最后,**寻找两个单链表的交点**问题。假设两个链表有交点,我们需要找到这个交点。一种方法是先分别遍历两个链表,记录各自的长度,然后从较长链表的头节点开始,按照长度差...
4. **处理循环部分**:当余数再次出现时,表明出现了循环,创建环链表。将余数对应的数字添加到链表末尾,并设置环连接。 5. **输出小数**:对于有限小数,直接遍历链表输出数字;对于无限循环小数,持续遍历环链表...
- 在判断链表是否相交时,可以用栈存储两个链表的节点,比较栈顶元素来确定交点。 在处理链表问题时,理解链表的基本操作(如遍历、插入、删除)至关重要,同时熟悉不同的算法策略可以帮助我们更高效地解决问题。...
13. **判断链表是否有环**:使用快慢指针(Floyd's Cycle-Finding Algorithm)来检测链表中是否存在环。 14. **找到环的起始节点**:如果链表有环,可以进一步找到环的起始节点。 15. **节点交换**:交换链表中两...
在C++编程语言中,链表是一种...源码可能还包括对链表的其他高级操作,例如查找链表的中间节点、判断链表是否有环、计算链表长度等。理解和掌握这些操作对于提升C++编程技能,特别是数据结构和算法方面的能力至关重要。
2. 链表环检测(Linked List Cycle, 如LeetCode的第141题):判断链表中是否存在环,并找出环的起点。 3. 两两交换链表中的节点(Swap Nodes in Pairs, 如LeetCode的第142题):将链表中相邻的节点两两交换。 4. ...
8. **判断单链表是否有环及环的起始点与长度** 使用Floyd判环算法(龟兔赛跑),两个指针分别以1倍和2倍速度前进,若相遇则存在环。确定环的起始点可让一个指针回到头节点,两者再次以相同速度前进,相遇点即为环...
1. 通过快慢指针寻找链表中点 - 这种方法适用于链表长度未知的情况,可以找到链表的中间节点,通常用于解决链表问题,例如判断链表是否有环。 2. 判断回文链表 - 可以通过前序遍历或利用快慢指针找中点后比较的方式...
检测链表中的环是一个经典的算法问题,通过快慢指针可以有效地解决。复制链表涉及到更复杂的数据结构理解,特别是当链表节点中包含指向其他节点的随机指针时。 数组的操作包括了基础的元素访问、插入、删除等,还...
6. **二级链表转一级链表**:遍历二级链表,将每个节点的子链表链接到一级链表的末尾。 7. **交换任意两个元素**:找到要交换的两个元素,交换它们的Data值,然后调整它们的Next指针,使其指向正确的后继节点。 8....
5. 判断链表状态(isEmpty,size):检查链表是否为空,获取链表长度。 6. 转换为字符串(toString):将链表转换为便于阅读的字符串格式。 7. 访问头尾节点(getHead,getTail):获取链表首尾节点。 以上就是...
如果链表有环,快指针会先到达环内的某个点,然后慢指针会在稍后相遇。如果没有环,快指针会先到达NULL。一旦两个指针相遇,我们就可以沿着慢指针回溯到环的入口,找到相交的第一个节点。 ```cpp ListNode* ...
对于判断链表是否有环的问题,可以利用快慢指针法,快指针每次前进两个节点,慢指针每次前进一个节点,如果两者相遇则说明链表有环。而对于寻找链表中间节点的问题,同样可以使用快慢指针,快指针速度是慢指针的两倍...
7. **判断链表是否相交**:如果链表不带环,可以分别遍历两个链表到尾部,记录长度,之后从长度短的链表头部开始,按长度差向另一个链表移动,直到相遇则相交,否则不相交。如果链表可能有环,可以使用 Floyd 环检测...
解决Joseph环问题通常使用循环链表,因为它能很好地模拟环形结构。链表的每个节点包含两个属性:密码(即成员的编号)和序号。通过循环遍历链表,找到报数到m的节点并删除,直至链表为空。在这个过程中,记录出列的...
对任意给定的图(顶点数不小于20,边数不少于30,图的类型可以是有向图、无向图、有向网、无向网),能够输入图的顶点和边(或弧)的信息,并存储到相应存储结构(邻接矩阵、邻接表、十字链表、邻接多重表,任选其中...
7. **判断链表相交**: - 对于没有环的链表,可以同时从两个链表的头节点开始遍历,直到它们相遇,说明链表相交。 - 如果链表可能有环,可以使用Floyd判断环的方法,同时使用快慢指针,如果快指针最终追上慢指针,...