这段代码如何在链表中找到循环?

时间:2011-02-13 13:13:49

标签: c data-structures linked-list

  

可能重复:
  Best algorithm to test if a linked list has a cycle

p=head;

q=head->next;
while(p!=NULL && q!=NULL)

{

if(p==q) { //Loop detected! exit(0); }

p=p->next;

q=(q->next)?(q->next->next):q->next; --how this line works ??

}

5 个答案:

答案 0 :(得分:1)

首先,如果列表中没有循环,则条件p==q将永远不会成立,因为q始终位于p的“前方”。

然后,pq之间的距离在每次迭代时增加1。因此,如果存在循环,则只要距离是循环长度的整数倍,条件p==q就为真。

有问题的行将q提前2个位置。它首先检查q在向前移动一个位置后是否不会到达列表末尾,以避免空指针解除引用。 (q->next位于q之前一个位置,q->next->next位于前方两个位置。)

答案 1 :(得分:0)

引用:

  

Q =(Q->下面)(Q->下一步 - >接着):Q->接下来; - 这条线有效吗?

这也可以是:

if(q->next) {
  q = q->next->next;
} else {
  q = q->next;
}

答案 2 :(得分:0)

如果你在链表中有一个循环,你可以通过在列表中运行两个指针找到它,一个通过列表前进一个元素,另一个通过两个元素。

如果没有循环,那么“更快”的循环将始终位于较慢的循环之前。如果有一个循环,它们最终将指向相同的元素,因为它们以不同的速度通过循环。

所有这一行

q=(q->next)?(q->next->next):q->next;

确实将更快的指针推进两个,如果可以的话,如果它不能,因为它接近这个列表的末尾,它只是前进一个。

在英语中,如果此元素不是最后一个,则将新指针设置为超出下一个的指针(可能为NULL)。如果此元素 是最后一个,请将其设置为下一个,为NULL。

我自己,我会把它写成:

q=(q->next)?(q->next->next):NULL;

但这只是风格问题。

答案 3 :(得分:0)

p总是在每次迭代中向前移动一步,但q向前移动两步(除非列表结束;因此检查是否存在q->next)。这意味着在每次迭代q都比p更远。如果列表中没有循环,q将只是到达列表的末尾,循环将终止。如果一个循环,那么q最终会循环遍历它(通过更快地前进)并“追赶”到p,即p == q将是真。

(如果你另外询问特定行的含义是什么,那么这只是一个较短的说法:

if (q-next) {
   q = q->next->next; // Go forward two steps if possible
} else {
   q = q->next; // Go forward one step otherwise
}

答案 4 :(得分:0)

这行代码:

q=(q->next)?(q->next->next):q->next;

可能会更改为:

q=(q->next)?(q->next->next):NULL;

所以这只是检查列表是否结束。如果是 - 比没有循环。