【问题标题】:Is my implementation of Floyd's cycle detection algorithm incorrect?我对弗洛伊德循环检测算法的实现不正确吗?
【发布时间】:2013-02-06 08:16:16
【问题描述】:

我有以下代码用于检测链表中的循环:

public Class Node {
    Object data;
    Node next = null;
}

boolean containCycle() {
    boolean retVal = true;
    Node head = this;
    Node slower = head;
    Node faster = head;

    if(faster != null && faster.next != null) {
        faster = faster.next;
    } else {    // there is only one element or zero element
        retVal = false;
    }

    if (faster.next != null) {
        faster = faster.next;
    } else {    // there are only 2 elements
        retVal = false;
    }

    while (slower != faster && slower != null && faster != null) {
        faster = (faster.next != null && faster.next.next != null) ? faster.next.next : null;
        slower = (slower.next != null) ? slower.next : null;
    }

    if (slower == faster) {
        retVal = true;
        System.out.printf("The two pointers meet at: %d\n", faster.data);
    } else {
        retVal = false;
    }

    if (retVal) {    // this is the part for detecting where the loop begins
        slower = head;
        while(slower.next != faster.next) {
            slower = slower.next;
            faster = faster.next;
        }
        System.out.println("The cycle starts at: " + slower.data);
    }

    return retVal;
}

这段代码一直运行良好,直到我真正开始检测循环开始的部分,我在代码中对此进行了注释。不知何故,这陷入了一个无限循环。

我怀疑这在某种程度上与 Java 中的引用传递有关?我在检测循环时是否更新了head 引用的值?我真的没有想法。请帮忙!

【问题讨论】:

    标签: java linked-list floyd-cycle-finding


    【解决方案1】:

    我不知道确切的算法,但您可以使用以下方式找到会合点。

    让我们将越来越慢的节点称为会合点。

    有两个指针,一个从头开始,另一个从交点开始。 并计算从头到会需要遍历多少个节点(让我们将此计数称为a)和 会面点的下一个节点到会面点。 (让我们将此计数称为b

    现在这两个计数中的差异|a-b| 代表共同部分-对吗? (即循环开始和越来越快的交汇点之间的部分)。

    所以现在重新开始。重置两个指针,一个指向头部,另一个指向会合点 + 1。

    例如如果a>b,则将指针从头部移动|a-b| 次,否则将指针从会议点移动+1 |a-b| 次。

    现在将两个指针一起移动,直到它们相遇。

    另一种解释方式

    由于您要查找的内容类似于您有两个链表并且它们在某个节点处合并并且您需要识别该节点的情况。 你所拥有的只是两个链表的起点。

    所以你从 head1 开始计数直到列表的末尾。 接下来从 head2 开始计数直到列表末尾。

    计算长度的差异。增加较长的路径差异时间。然后从较短的路径 head 和 diff 开始移动指针,直到两个指针相遇。

    这与您在另一种情况下所做的基本相同。

    【讨论】:

    • 这是我正在使用的确切算法,只是不知何故我的后半部分(查找循环头)的实现不起作用,并导致无限循环。我尝试了很多不同的东西,但它们都不能正常工作,所以我想知道到底发生了什么......
    • 但是你的增长速度越来越慢,这没有任何意义。
    • 对不起,如果他们的名字令人困惑,那是因为我在第一部分使用它们来检测是否真的有一个循环。一旦我确认一个循环的存在,我将较慢的一个移到头上,在集合地点保持较快,然后将它们每一步移动一个。这就是您的算法所描述的内容。
    • 我明白这一点。但我不明白的是,你为什么要同时 1 比 1 更慢(从头部开始)和更快(从集合地点开始)移动。他们永远不会相遇 - 对吗?
    • 我的算法说先从头到会的地方慢一点,数一下。然后从会场+1更快地移动到会场,数数。然后计算差异,最后将它们移动在一起,直到它们合并。
    猜你喜欢
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    相关资源
    最近更新 更多