在Python中实现不相交集系统

时间:2011-02-23 18:04:48

标签: python merge find disjoint-sets

到目前为止我所做的主要是基于Cormen等人的“算法导论”第571页。

我在python中有一个Node类,代表一个集合:

class Node:
    def __init__(self, parent, rank = 0):
        self.parent = parent
        self.rank = rank

此实现将使用List节点作为森林(我愿意更好地存储集合)。

Initialize()返回一个节点列表,我将存储在变量set中并传递给其他函数。

Find在林中搜索值并返回它出现的集合。我选择使用for s in range(len(set)):,这样在递归中我可以缩小由{传递的集合列表{1}}。

set[s:]

def Find(set, value): for s in range(len(set)): if value != set[s].parent: set[s].parent = Find(set[s:], set[s].parent) return set[s]通过查找它们并推广排名较高的集合来合并林中的集合。

Merge

我在def Merge(set, value1, value2): set_val_1 = Find(set, value1) set_val_2 = Find(set, value2) if set_val_1.rank > set_val_2.rank: set_val_2.parent = set_val_1 else: set_val_1.parent = set_val_2 if set_val_1.rank == set_val_2.rank: set_val_2.rank += 1Find时遇到了一些错误,即Merge没有返回正确的设置,所以我不确定Find工作正常。我希望得到一些帮助,以确保功能正确实施。

5 个答案:

答案 0 :(得分:4)

您是否看过其他任何existing implementations

答案 1 :(得分:2)

我没有这本书的最新版本,但这看起来并不像一个不相交的森林。

我认为你的错误是认为森林必须存储在一个集合中,你必须遍历这个集合才能在节点上进行操作。从setMerge()移除Find()并将Find()实施为

def Find(n):
    if n != n.parent:
        n.parent = Find(n.parent)
    return n.parent

就像在书中一样。然后添加一个MakeSet(),它返回一个正确初始化的节点,也可能是一个SameSet()函数:

def SameSet(n1, n2):
    return Find(n1) == Find(n2)

您现在有一个工作的不相交集实现。

答案 2 :(得分:2)

假设每个节点都被初始化为它自己的父节点:

def Find(node):
    while node is not node.parent:
        node = node.parent
    return node

答案 3 :(得分:1)

使用这个implementation作为起点,我创建了一个新的python类来处理不相交的集合,它也支持使用MongoDb的持久性。

在课堂上你应该能够:

  • 创建UnionFind()的实例,默认情况下使用python内置词典,稍后在MongoDb集合中决定consolidate()您的结果
  • 从MongoDb集合创建UnionFind实例并直接使用它。

您可能需要查看the code on github

干杯, 西蒙

答案 4 :(得分:0)

维基百科page为不相交集数据结构上的基本operations提供了伪代码。这是Python的直接端口(采用路径压缩和按等级合并):

class Node:
    """Represents an element of a set."""
    def __init__(self, id):
        self.id = id
        self.parent = self
        self.rank = 0
        self.size = 1

    def __repr__(self):
        return 'Node({!r})'.format(self.id)


def Find(x):
    """Returns the representative object of the set containing x."""
    if x.parent is not x:
        x.parent = Find(x.parent)
    return x.parent


def Union(x, y):
    """Combines the sets x and y belong to."""
    xroot = Find(x)
    yroot = Find(y)

    # x and y are already in the same set
    if xroot is yroot:
        return

    # x and y are not in same set, so we merge them
    if xroot.rank < yroot.rank:
        xroot, yroot = yroot, xroot  # swap xroot and yroot

    # merge yroot into xroot
    yroot.parent = xroot
    xroot.size += yroot.size
    if xroot.rank == yroot.rank:
        xroot.rank = xroot.rank + 1

演示:

>>> a, b, c = map(Node, 'abc')
>>> Find(a), Find(b), Find(c)
(Node('a'), Node('b'), Node('c'))
>>> Find(a).size
1
>>> Union(a, b)
>>> Union(b, c)
>>> Find(a), Find(b), Find(c)
(Node('a'), Node('a'), Node('a'))
>>> Find(a).size
3