我不知道如何通过Linked list实现Disjoint-set数据结构?谁能告诉我? 我特别困惑的是find-set()如何在这种实现中工作O(1).thx~
答案 0 :(得分:6)
虽然不相交集数据结构通常被解释为树林,但它通常用数组实现:一个数组用于将索引映射到其父级索引,另一个数组用于将索引映射到其排名。这消除了许多毫无意义的开销(在空间和时间上),这在理论上是不相关的,但它在实践中。您可能需要一种方法来在索引和某种对象的实例之间进行映射。
顺便说一句, find
在O(1)中不起作用。排名的技巧阻止find
采用线性时间,但在最坏的情况下它仍然可以采用对数步数。 O(α(n))时间是一个摊销时间,解释它的来源是很棘手的 - 你可以在一个好的但不是线性的集合联盟算法[Tarjan]的效率中找到分析。
这是一种可行的方式:
disjoint_set {
int[] parent, rank;
makeset(int n)
{
rank = new int[n];
parent = new int[n];
for(int i = 0; i < n; i++)
parent[i] = i;
}
int find(int i)
{
if (parent[i] != i)
parent[i] = find(parent[i]);
return parent[i];
}
void union(int x, int y)
{
x_root = find(x);
y_root = find(y);
if (x_root != y_root) {
if (rank[x_root] < rank[y_root])
parent[x_root] = y_root;
else if (rank[x_root] > rank[y_root])
parent[y_root] = x_root;
else {
parent[y_root] = x_root;
rank[x_root]++;
}
}
}
}
答案 1 :(得分:1)
不相交的设置数据结构在每次操作的O(1)时间内都不起作用。相反,它在O(1)时间内通过大量操作。
每个节点都存储一个指向其父节点的指针,每个不相交集的代表元素是您尽可能遵循父指针的节点。要获得O(1),您必须折叠父节点的链,以便每当您跟随父链接时,每个元素都指向头节点。
这是一些完成所有这些操作的Python代码。特别注意head
方法中的第二个while循环:这是使数据结构高效工作的关键。
class Node:
def __init__(self, value):
self.value = value
self.parent = None
def head(self):
head = self
while head.parent:
head = head.parent
while self != head:
self.parent, self = head, self.parent
return head
def union(a, b):
if a.head() != b.head():
a.head().parent = b.head()
nodes = [Node(i) for i in range(10)]
nodes[0].union(nodes[1])
nodes[0].union(nodes[2])
print set(node.head().value for node in nodes)