【问题标题】:Could Kruskal’s algorithm be implemented in this way instead of using a disjoint-set forest?Kruskal 的算法能否以这种方式实现,而不是使用不相交集森林?
【发布时间】:2019-02-02 14:23:06
【问题描述】:

我正在从this geeksforgeeks article 学习 Kruskal 的 MST。给出的步骤是:

  1. 按权重的非递减顺序对所有边进行排序。

  2. 选择最小的边。检查它是否与到目前为止形成的生成树形成一个循环。如果没有形成循环,则包括该边。否则,丢弃它。

  3. 重复步骤 (2),直到生成树中有 (V-1) 条边。

我真的觉得没有必要使用不相交集。代替检查循环,我们可以将顶点存储在访问数组中,并在选择边缘时将它们标记为真。如果我们发现一条边的两个顶点都在访问数组中,则循环通过程序,我们将忽略该边。

换句话说,我们不能存储一个位数组,而不是存储一个不相交的森林,而是存储一个位数组,指示哪些顶点在之前的某个步骤中已链接到另一条边?

【问题讨论】:

    标签: algorithm minimum-spanning-tree kruskals-algorithm


    【解决方案1】:

    您所描述的方法并非在所有情况下都能正常工作。例如,考虑这个折线图:

    A - - B - - C - - D
    

    假设 A-B 的权重为 1,C-D 的权重为 2,B-C 的权重为 3。Kruskal 的算法在这里会做什么?首先,它会添加 A - B,然后是 C - D,然后是 B - C。

    现在想象一下你的实现会做什么。当我们添加 A - B 时,您会将 A 和 B 标记为已访问。然后当我们添加 C - D 时,您会将 C 和 D 标记为已访问。但是当我们尝试添加 B - C 时,由于 B 和 C 都被访问了,您将决定不添加边,从而留下未连接的结果。

    这里的问题是,在构建 MST 时,您可能会添加连接过去已经链接到其他节点的节点的边。因此,添加边的标准更少“这些节点以前是否链接过?”以及更多“这些节点之间是否已经存在路径?”这就是不相交的森林的用武之地。

    很高兴您正在探索和推动传统的实现,并试图找到改进它们的方法。如果你这样做了,你会学到很多关于这些算法的知识!在这种情况下,碰巧你提出的建议并不完全奏效,而了解它为什么不起作用有助于阐明为什么现有方法是这样的。

    【讨论】:

    • 我也在考虑使用visited[] 数组。感谢这个角落案例@templatetypedef
    【解决方案2】:

    我真的觉得没有必要使用不相交集。代替检查循环,我们可以将顶点存储在访问数组中,并在选择边缘时将它们标记为真。如果我们发现一条边的两个顶点都在访问的数组中,则循环通过程序,我们将忽略该边。

    是的,你当然可以这样做。在该算法中使用不相交集的要点是性能。与使用 List 相比,使用合适的不相交集实现会产生更好的渐近性能。

    【讨论】:

    • 在这两种情况下都是 ElogE。我的算法的时间复杂度 -> 1. ElogE 用于排序 2. O(E) 用于迭代边缘,结果是 ElogE。
    • @VedantDixit - 您需要为添加的每条边搜索循环,因此您的方法是 O(EV) 来查找循环。
    • 您忽略了在每次迭代中搜索列表的 O(V) 成本,@VedantDixit。这样做 O(E) 次主导了整个算法的成本:O(V * E)。检查不相交集中成员的摊销成本取决于实现,但它很容易为 O(1),产生总成本 O(E log E)。
    • 我可以在 O(1) 中完成。看上面我的方法。检查两个顶点是否存在于 O(1) 乘以 E 得到 O(E) 的访问数组中。
    • 我的感觉是 OP 提出了一种不同的策略来确定路径是否存在,而不是你在这里解决的问题。我认为一旦它们链接到其他任何东西,它们就会将节点标记为关闭,而不是显式检查路径。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2014-10-26
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    相关资源
    最近更新 更多