我在Python中实现了一个不相交的集合系统,但我已经碰壁了。我正在为系统使用树实现,并且正在为系统实现Find(),Merge()和Create()函数。
我正在实施排名系统和路径压缩以提高效率。
问题在于,这些函数必须将一组不相交的集合作为参数,从而使遍历变得困难。
class Node(object):
def __init__(self, value):
self.parent = self
self.value = value
self.rank = 0
def Create(values):
l = [Node(value) for value in values]
return l
Create函数接受一个值列表并返回包含相应数据的单个节点列表。
我认为Merge函数看起来与此类似,
def Merge(set, value1, value2):
value1Root = Find(set, value1)
value2Root = Find(set, value2)
if value1Root == value2Root:
return
if value1Root.rank < value2Root.rank:
value1Root.parent = value2Root
elif value1Root.rank > value2Root.rank:
value2Root.parent = value1Root
else:
value2Root.parent = value1Root
value1Root.rank += 1
但我不确定如何实现Find()函数,因为需要将节点列表和值(不仅仅是一个节点)作为参数。查找(设置,值)将成为原型。
我理解当Node作为Find(x)的参数时如何实现路径压缩,但这种方法让我失望。
非常感谢任何帮助。谢谢。
编辑澄清。
答案 0 :(得分:2)
当您意识到操作union和find也可以作为不相交的set林类的方法而不是单个不相交的集合实现时,这种数据结构的实现变得更加简单。
如果您可以阅读C ++,那么请查看my take on the data structure;它隐藏了来自外部世界的实际集合,仅将它们表示为API中的数字索引。在Python中,它将类似于
class DisjSets(object):
def __init__(self, n):
self._parent = range(n)
self._rank = [0] * n
def find(self, i):
if self._parent[i] == i:
return i
else:
self._parent[i] = self.find(self._parent[i])
return self._parent[i]
def union(self, i, j):
root_i = self.find(i)
root_j = self.find(j)
if root_i != root_j:
if self._rank[root_i] < self._rank[root_j]:
self._parent[root_i] = root_j
elif self._rank[root_i] > self._rank[root_j]:
self._parent[root_j] = root_i
else:
self._parent[root_i] = root_j
self._rank[root_j] += 1
(未经测试。)
如果您选择不遵循此路径,则代码的客户端确实必须了解Node
和Find
必须采用Node
参数。
答案 1 :(得分:0)
显然merge
函数应该应用于节点对。
所以find
函数应该采用单节点参数,如下所示:
def find(node):
if node.parent != node:
node.parent = find(node.parent)
return node.parent
wikipedia has pseudocode也很容易转换为python。
答案 2 :(得分:0)
始终在项目上完成查找。查找(项目)定义为返回项目所属的集合。因此合并不能占用节点,合并总是需要两个项目/集合。合并或联合(item1,item2)必须首先找到(item1)和find(item2),它们将返回每个属于的集合。之后,必须将由向上树表示的较小集合添加到较高的集合中。发出查找时,始终回溯路径并压缩它。
经过测试的路径压缩实现是here。