有没有算法可以只使用两个变量来遍历链表并查找它是否与自身形成循环。假设您有一个由对象组成的链表,对象类型不重要。我有一个指向链表头部的指针存在一个变量中,我只能使用另一个变量来遍历整个列表。
我的计划是比较指针值以查看是否有相同的指针。该链表的大小是有限的,但可能非常大。我可以将两个变量都设置为头部,并使用另一个变量遍历列表,始终检查它是否等于另一个变量,但如果我碰到循环,我将无法跳出它。我认为这与遍历列表和比较指针值的速率不同有关。有什么想法吗?
有没有算法可以只使用两个变量来遍历链表并查找它是否与自身形成循环。假设您有一个由对象组成的链表,对象类型不重要。我有一个指向链表头部的指针存在一个变量中,我只能使用另一个变量来遍历整个列表。
我的计划是比较指针值以查看是否有相同的指针。该链表的大小是有限的,但可能非常大。我可以将两个变量都设置为头部,并使用另一个变量遍历列表,始终检查它是否等于另一个变量,但如果我碰到循环,我将无法跳出它。我认为这与遍历列表和比较指针值的速率不同有关。有什么想法吗?
我建议使用 Floyd's Cycle-Finding Algorithm
,又称为The Tortoise and the Hare Algorithm
。它的时间复杂度为O(n),我认为它符合您的要求。
示例代码:
function boolean hasLoop(Node startNode){
Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2) return true;
slowNode = slowNode.next();
}
return false;
}
更多信息请参见维基百科:弗洛伊德循环查找算法。
fastNode
已经越过了slowNode
吗?”- 可以的。 “这样(一次跳多个步骤)不会是更好的算法吗?”- 不一定。考虑两种极端情况。链表A是一个有1000000个节点的大循环。链表B有一个非循环的包含1000000个节点的链,最终到达一个只有三个节点的小循环。加速兔子将让您更快地检测到A中的循环(兔子比乌龟更早地完成一圈),但代价是使您在检测B中的循环时变慢(等待乌龟甚至到达循环的时间更长,而兔子则疯狂地在圆圈里奔跑)。这是一个权衡。 - Mark Amery当然可以。一种解决方案是使用两个指针遍历列表,其中一个指针的移动速度是另一个的两倍。
从列表中的任何位置开始,将“慢”指针和“快”指针指向同一个位置。运行遍历循环。如果“快”指针在任何时候与慢指针重合,则表示您有一个循环链表。
int *head = list.GetHead();
if (head != null) {
int *fastPtr = head;
int *slowPtr = head;
bool isCircular = true;
do
{
if (fastPtr->Next == null || fastPtr->Next->Next == null) //List end found
{
isCircular = false;
break;
}
fastPtr = fastPtr->Next->Next;
slowPtr = slowPtr->Next;
} while (fastPtr != slowPtr);
//Do whatever you want with the 'isCircular' flag here
}
static const
结构或内存映射只读文件),或者如果列表被多个线程使用(只要访问是只读的,就不需要锁定;如果加锁,它将变得非常缓慢和/或阻塞其他线程)。 - R.. GitHub STOP HELPING ICEint isListCircular(ListNode* head){
if(head==NULL)
return 0;
ListNode *fast=head, *slow=head;
while(fast && fast->next){
if(fast->next->next==slow)
return 1;
fast=fast->next->next;
slow=slow->next;
}
return 0;
}
boolean findCircular(Node *head)
{
Node *slower, * faster;
slower = head;
faster = head->next;
while(true) {
if ( !faster || !faster->next)
return false;
else if (faster == slower || faster->next == slower)
return true;
else
faster = faster->next->next;
}
}