所以我到处都看到加权联合查找算法,他们使用这种方法:
这里的时间复杂度是O(lgN)
现在对此进行优化是使树变平,即,每当我计算特定节点的根时,都应将该路径中的所有节点设置为指向该根。
时间复杂度为O(lg * N)
我可以理解,但是我不明白的是为什么它们不以数组/哈希集开始,其中节点指向根(而不是直接父节点)?这样会使时间复杂度降低到O(1)。
答案 0 :(得分:0)
我将假设您要求的时间复杂度是检查2个节点是否属于同一集合的时间。
关键在于如何连接集合,具体来说,您以一个集合的根(较小的集合)为根,并使其指向另一集合的根。让两个集合分别以p
和q
作为根,如果|p|
是根,则p
代表集合p
的大小,而{通常,它是设置路径经过p(即1 +所有子项)的项数。
我们可以不失一般性地假设|p| <= |q|
(否则我们只交换它们的名称)。然后,我们有了那个|p u q| = |p|+|q| >= 2|p|
。这向我们显示了数据结构中的每个子树最多可以是其父树的一半,因此,给定N
个项目,它最多可以具有深度1+lg N = O(lg(N))
。
如果两个选择的项目离根最远,则将需要O(N)
个操作来找到它们每个集合的根,因为您只需要O(1)
个操作即可向上移动一层在集合中,然后进行O(1)
操作以比较那些根。
此成本也适用于每个联合操作本身,因为您需要确定需要合并的两个根。我们没有让所有节点都直接指向根的原因有很多方面。首先,每次执行联合时,我们都需要更改集合中的所有节点,其次,我们只有从节点指向根的边而不是其他方式,因此我们必须查看所有节点才能找到它们我们需要改变。下一个原因是我们有很好的优化,可以帮助您进行此类操作,并且仍然有效。最终,如果确实需要,您可以在最后执行这样的步骤,但是执行它会花费O(N lg(N))
时间,这与在没有运行时间短的情况下自行运行整个算法需要多长时间比较裁剪优化。
答案 1 :(得分:0)
您所建议的解决方案将把Find操作的时间复杂度降低到O(1)是正确的。但是,这样做会使联合操作的速度变慢。
想象一下,您使用数组/哈希表来记住每个节点的代表(或称其根)。当您在两个节点x
和y
之间执行联合操作时,您将需要更新具有与x
相同的代表的所有节点以具有y
的代表, 或相反亦然。这样,并集在O(min{|Sx|, |Sy|})
中运行,其中Sx
是与x
具有相同代表的节点集。这些集合可能比log n
大得多。
另一方面,加权并集算法的Find和
均具有O(log n)
这是一个权衡。如果您希望执行很多“查找”操作,但是执行的“联合”操作很少,则应使用建议的解决方案。如果您希望每个都做很多,则可以使用加权联合算法来避免操作过慢。