如何在链表的循环开始时找到节点?

时间:2018-08-23 23:04:58

标签: c++ algorithm linked-list

从“破解编码面试”中,有一个练习说:

给出一个循环链表,实现一种算法,该算法在循环开始时返回节点。

循环链表的定义:一种(损坏的)链表,其中节点的下一个指针指向较早的节点,以便在链表中进行循环。

算法答案基本上是使用慢跑者和快跑者来遍历链接列表以查看其是否循环。如果慢速奔跑者和快速奔跑者发生碰撞,它将循环,因此您可以在循环开始时找到该节点。 (如果它们不发生冲突,那么快速奔跑者最终将到达链表的末尾,这意味着没有循环。)

但是,这本书找到循环开头节点的位置的答案取决于假设,即链表具有大小为k的“非循环”部分。一旦慢速跑步者和快速跑步者发生冲突,就可以将慢跑步者移动到链接列表的开头。您以相同的速度迭代两个对象,直到它们发生冲突。它们碰撞的位置是循环开始处的节点。

我的问题是,假设链表具有大小为k的“非循环”部分,是否可以找到循环开始处的节点在哪里?还是我必须假设存在大小为k的“非循环”部分?

3 个答案:

答案 0 :(得分:2)

对于这个问题,我有2个答案,
一个:
如果在列表中有大小为k的循环,则如果将指针k的一个指针从头部移开,将另一个指针从头部移动,然后将它们一起移动,则当其中一个指针进行完整循环时,最后将其移动,而另一个指针刚刚开始循环,然后这就是它们在循环开始时相遇的原因。您需要做的就是计算循环中的节点数。
第二:
我通过示例介绍了我的解决方案:
假设我们得到以下列表: list.
使用较快和较慢的流道方法查找通用指针。 假设它们在节点号7中相遇。 完成后,将删除节点7的下一个指针(作为列表的末尾)。 现在,我们可以简化为解决该问题的另一个问题,那就是在两个链接列表中找到第一个公共元素,即它们的末尾是“节点8”的指针,而其中一个的头是列表的头(节点0),而另一个列表头是“节点8”。
看起来像这样: this.

您可以通过以下步骤解决问题:
1)获取第一个列表中节点的数量,让数量为c1。
2)获取第二个列表中节点的计数,让计数为c2。
3)获得计数差d = abs(c1 – c2)
4)现在从第一个节点到d个节点遍历更大的列表,以便从此处开始,两个列表的节点数均相等。
5)然后,我们可以并行遍历两个列表,直到遇到一个公共节点。 (请注意,获取公共节点是通过比较节点的地址来完成的。)

答案 1 :(得分:1)

除非书中特别假定存在{em> positive ,例如kk也可以为零。

这里是k = 0的非正式论证:

假设整个列表是一个循环。
如果快速跑步者的速度是慢跑步者速度的两倍,则当慢跑步者完成一个循环而快跑步者完成两个循环时,它们将发生碰撞。
如果再从头开始慢跑者,则两者将立即在第一个节点上发生碰撞。

答案 2 :(得分:0)

我对那本书不熟悉,但是我认为你读的不正确。可能 k 是循环的大小,算法的工作原理如下:

  1. 使用Floyd或Brent算法检测循环。 (都在这里描述:https://en.wikipedia.org/wiki/Cycle_detection
  2. k 为循环的大小的倍数,以便一旦进入循环,如果出现以下情况,您将回到相同的节点您进行了 k 个步骤。您可以在找到周期后进行测量,也可以在寻找周期时仅计算“快速指针”和“慢速指针”之间的步长差异。
  3. 将2个指针放在列表的顶部(再次将它们分别称为快和慢),然后将“快”指针前进 k 次。
  4. 快速指针和慢速指针指向不同的节点时,将它们按锁定步长前进,以使快速指针总是 k 个步长。

只要慢速指针进入循环,算法就会停止-循环前进可以再次到达第一个节点。