【问题标题】:if edge weights uniformly distributed between 0 and 1 prims or kruskals如果边缘权重均匀分布在 0 和 1 个 prims 或 kruskals 之间
【发布时间】:2013-06-09 16:18:36
【问题描述】:

假设图 G 中的边权重均匀分布在 [0,1) 上。哪种算法 prims 或 Kruskals 会更快? 我认为这将是 kruskals,因为我们可以利用特定的排序算法,因为排序是 kruskals 算法的瓶颈步骤。

【问题讨论】:

  • 我不明白均匀分布将如何帮助您进行排序;你仍然可能有不同的价值观。
  • 您也可以参考这里stackoverflow.com/questions/1195872/kruskal-vs-prim。偏好实际上取决于图形是否像其他人指出的那样密集。
  • @G.Bach 它有帮助,因为您可以使用基数排序在线性时间进行排序,成功概率极高。看我的回答。
  • 如果您是生成数字的人,您可以按排序顺序生成它们,而不是排序。

标签: algorithm prims-algorithm kruskals-algorithm


【解决方案1】:

这是您必须进行基准测试的东西。您可以使用花哨的数据结构(van Emde Boas 树)和排序算法(一些计数排序变体)将两种算法的理论预期复杂度降低到更接近线性的程度。但是,尚不清楚任何此类技巧是否可以提高任一算法的实际性能。提高内存局部性的恶作剧可能会产生更大的影响。

【讨论】:

  • 看我的回答。这是 CLRS 中的一个练习,作者特意要求一些技巧。
  • @xdavidliu 鉴于这是一个纯理论练习(cs.stackexchange.com 会是一个更好的论坛),考虑如果 Kruskal 的输入是一棵树,它可以在线性时间内运行.开箱即用,Karger-Klein-Tarjan '95 在预期的线性时间内为您提供正确的树。但是随机输入采用了更简单的算法:处理度数为 1 和度数为 2 的顶点,然后在边缘值
  • 如果输入是一棵树,那么 MST 就是树本身,对吧?
  • 是的,但是在这个问题中,您需要运行 Kruskal 或 Prim。 :)
【解决方案2】:

边权重的分布无关紧要。

Prims 和 Kruskals 的主要区别在于 Prim 的算法运行时间与顶点数的平方成正比,而 Kruskal 的算法运行时间与边数和边数的对数的乘积成正比。因此,Prim's 在密集图上更快,而 Kruskal's 在稀疏图上更快。

例如,如果您有 1000 个顶点 3000 条边(稀疏),那么 Prim 将为 K1 * 1,000,000,而 Kruskal 将为 K2 * 24,000。但是如果你有 1000 个顶点和 250,000 条边(密集),那么 Kruskal 将是 K2 * 3,100,000。

【讨论】:

  • 使用斐波那契堆 (en.wikipedia.org/wiki/Prim's_algorithm#Time_complexity),Prim 的运行时间可以进一步减少到 E + V Log V。
  • 这家伙有一枚铜牌,他不打算开始编写 FH 实现,而且无论您使用什么数据结构,Kruskal 的算法总能在足够稀疏的图上击败 Prim 的算法。
  • @TylerDurden 成为 SO 的新用户并不意味着对计算机科学和/或编程不熟悉。另外,除非您是严格意义上的非正式含义,否则您想到了densesparse 的哪个定义?我意识到可以从两种算法使用的变体的复杂性中推导出哪种算法更快的图类,但是明确指定这些类将是您答案的一个很好的补充。
  • 如果 OP 不清楚他的图是稀疏还是密集,那么选择哪种算法可能不会对执行时间产生显着影响。
  • 所以基本上这个答案的意思是边缘权重具有一定分布的事实是无关紧要的?
【解决方案3】:

更新 2 正如@David Eisenstat 在下面的评论中指出的那样,在 O(E) 时间内进行排序的更简单的方法是使用 |E| 进行桶排序。桶。区间 [0, 1) 可分为 |E|长度为 1/|E| 的桶每个,编号为 0、1、2 ... |E|-1,区间内的任何权重 w 都属于编号为 k = floor(|E| w) 的桶。每个桶中的预期权重数量为 O(1),因此可以使用 |E| 进行排序每个插入排序的大小为 O(1),因此这给出了 O(E alpha(V)) 的预期时间 Kruskal 算法。

注意:作为@G。 Bach 指出,上述假设可以在 O(1) 时间内执行权重和 floor(|E|w) 浮点乘法的比较,这可能需要一定的怀疑。对于非常大的 |E| 值,这两个操作可能仍然有 O(lg E) 的贡献。

更新 正如 G. Bach 在下面指出的那样,第一轮 O(1) 位基数排序后的 bin 大小将始终是 Omega(E),所以下面的答案在技术上不是保证在 O(E) 时间内排序。但是,可以选择小于 O(lg E) 的位数,也许是 O(lg lg E) 或 O(sqrt lg E)?这样排序所需的时间少于 O(E lg E) 的预期时间。

原始答案

这是 CLRS 中的练习 23.2-6。我很确定 Kruskal 会更快(因此这里的其他答案是错误的)。权重的分布确实很重要;无关紧要的是图的密度/稀疏度。

普通版本主要是 O(E lg E) 时间从边缘权重排序。当边缘权重从均匀分布中提取时,我们可以对某个恒定位数执行基数排序,然后通过进一步的基数排序来修复连续子数组中的冲突。那是 O(E) 时间。

然后,剩下的就是普通的 Kruskal:使用具有联合秩和路径压缩的不相交集(如 CLRS 的第 23 章)剩下的工作是 O(E alpha(V)),其中 alpha(V) 是逆Ackermann 函数,并且对于任何正常的 V 值都

因此,对于基数排序,Kruskal 是线性 O(E),概率任意接近 1

关于基数排序的注意事项:

可以通过使用更多位数使预期的碰撞次数(即前 15 位相同的边权重)任意小,但如果位数为 O(lg E),则为 O(1)。当然,这意味着 O(E lg E) 基数排序,这会破坏目的。但是,我们实际上并不需要完全避免碰撞,只需限制它们的大小,以便它们可以在线性时间内修复。

因此,我们可以考虑在一轮“基数排序”中对一些恒定位数(如 15)进行排序,这会将权重数组分成具有相同 15 位数字的连续子数组(也称为“bins”),然后在下一轮,使用第二“轮”基数排序对每个子数组的 16-30 位进行排序。

正式证明将涉及与生日悖论类似的计算,但由于冲突的概率随着使用的额外数字的数量呈指数下降,因此应该可以使用 O(1)“轮数”对上述内容进行完全排序,即将导致 O(E) 总排序时间。

【讨论】:

  • +1 这个答案非常密集。固定位数的基数排序是 O(E),但它有一个(因为统一的分布。)以错误顺序留下一些权重的微小机会,因为它们具有用于基数排序的相同数字前缀(“基数”)。如果我理解正确,您会说通过在实际进行基数排序之前选择对具有相同基数的权重进行排序来解决这个问题;你如何在 O(E) 中做到这一点?另外,我认为基数排序冲突的预期数量并不总是 O(1),这不应该取决于 E 和基数位数吗?
  • 谢谢,这清除了一些。再想一想,无论输入如何,平均“bin 大小”将是 E/(2^(用于基数排序的位数)),对于用于基数排序的任何恒定位数仍然是 Ω(E) ,并且在某些时候,您必须进行比较排序或考虑基数排序的字长。我不认为基数排序最终有助于时间复杂度,但由于您指出的原因,无论如何都有很大的机会提高性能 - 几乎可以保证均匀分布为我们提供均匀分布的权重,这有助于基数排序。跨度>
  • @G.Bach 关于 O(1) 位的 Omega(E) 预期 bin 大小,这是一个很好的观点。因此,使用 O(lg E) 数字肯定会将预期的 bin 大小降低到 O(1),但是基数排序本身会占用 O(E lg E) 并破坏目的。但是,我想知道是否可以在两者之间使用一些东西,也许是 O(lg lg E) 数字或其他东西,所以预期的排序运行时间仍然很少 o(E lg E)?
  • @xdavidliu 到目前为止,我认为机器模型太模糊了,我无法弄清楚如何处理这个问题;如果数字中有无限多的数字,比较/算术运算仍然需要 O(1) 吗?这似乎不合适,尤其是另一方面,如果我们在分析基数排序复杂性时考虑了字长;我们不会用相同的标准来衡量。我们应该把位数限制在 E 的某个函数上吗?不确定。
  • 这些都是非常有效的观点。我很确定桶排序解决方案是 CLRS 的作者在这里想要的,但如果它确实需要不切实际的假设,比如 O(1) 浮点算术和任意精度的比较,那么这可能需要在他们的勘误表中输入.然而,问题的陈述是相当开放的,他们从未真正声称 O(E) Kruskal 是可能的,因此 CLRS 仍然保留合理否认的权利。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多