我正在尝试尽可能高效地实施Kruskal。
为了提高运行效率,使用堆或排序算法对边缘进行排序是否有区别?
还有哪些其他技术可以让Kruskal算法更有效地工作?
答案 0 :(得分:3)
这取决于您要解决的确切问题。如果您要实现通用解决方案,只需选择“最快”的排序算法。我怀疑那是不是heapsort。我会默认使用Java正在使用的任何排序算法(如果你正在排序对象,可能是timsort)。此外,在某些情况下,排序可以比O(ElogE)
更快地完成。假设你的边缘只能有一个小间隔的整数权重,那么你可以选择与countort非常相似的东西。因此,如果您处于其中一种情况,那么堆可能不是一个好选择。 另外,我看不出有人会单独在Kruskal算法的上下文中使用堆。
要回答你的第二个问题(但你可能已经知道了),Disjoint-set data structure对集合操作的使用给出了很好的加速。它具有各种优点:易于实现,良好的渐近行为和低常数。
修改强>
我已经重新考虑了堆/ heapsort选项,主要是由于我的帖子上的评论。如果只排序直到树完成,使用堆可能会带来巨大的优势。 180度打开我的意见。这就是原因。
考虑Erdős–Rényi model。现在,这是一个非常简单的模型,其中一个以G
个顶点上的空图n
开头(即没有边),并将每个可能的边加上概率p
到{{1} },独立于任何其他边缘。这并不是Kruskal的算法在编写树时所做的事情,但如果G
具有二次数的边(就顶点数而言),它就像'相当好',边缘分布不是'偏向的'并且权重分配不是“有偏见的”。
现在这里有趣的部分。在Erdős-Rényi模型下,当G
大约为p
时(即,在向图表添加ln(n)/n
边后'粗略'说话),图表就会连接起来。结果众所周知(检查here)。
尽管Kruskal算法的设置有所不同,但如果O(nln(n))
具有二次边数(就顶点数而言),则边缘分布不是“偏向”且权重分配是没有“偏见”,在G
个边缘内可以到达树是合理的。如果确实如此,那么在开始编写树之前,它会使用堆并仅对树进行排序,直到比使用比较排序方法对整个边集进行排序更好。
因此,使用堆可能会使运行时速度提高,而且可能相当可观。