python实现一个简单的并查集的示例代码

  • Post category:Python

下面给出具体的 Python 实现一个简单的并查集的示例代码攻略。

什么是并查集?

并查集(Disjoint Set)是一种用于解决一些等价类问题的数据结构,它支持查询、合并等操作。所谓“等价类问题”,就是在很多元素中,有一些元素之间会互相关联,我们想要知道哪些元素之间有关联,哪些元素之间没有关联。用并查集可以快速处理这个问题。

并查集通用操作

并查集中常用的操作有以下三个:

  1. 初始化操作:通常是初始化每个元素自己成为一个单独的集合。
  2. 查找操作:即确定某个元素所属的集合。
  3. 合并操作:将两个元素所在的集合合并成一个集合。

Python 实现一个简单的并查集

接下来,我们将使用 Python 实现一个简单的并查集,我们会依次给出“初始化操作”、“查找操作”和“合并操作”的代码解释。

初始化操作

在初始化过程中,我们需要定义一个数据结构,记录每个元素所属的集合。这里我们可以用一个数组来表示每个元素所属的集合,这个数组的下标就表示元素的编号,值则表示该元素所属的集合的编号。

class UnionFindSet:
    def __init__(self, n):
        self.father = [i for i in range(n)]

其中,father 数组的初始值是数组下标本身。这意味着,初始时,每个元素都属于自己单独的一个集合。

查找操作

查找操作即确定某个元素所属的集合。在查找操作中,我们需要遍历所有的父节点,检查该节点是否为自己的父节点,直到找到根节点。这个过程可以用递归实现。

def find(self, x: int) -> int:
    if self.father[x] == x:
        return x
    self.father[x] = self.find(self.father[x])
    return self.father[x]

在实现过程中,我们使用了路径压缩的技巧,将所有经过节点的父节点全部更新为根节点,以后再查询该节点时就会更快。

合并操作

合并操作将两个元素所在的集合合并成一个集合。合并操作需要先查找两个元素所属的集合,然后将其中一个元素的根节点指向另一个元素的根节点即可。

def union(self, x: int, y: int):
    root_x, root_y = self.find(x), self.find(y)
    if root_x != root_y:
        self.father[root_x] = root_y

以上就是 Python 实现一个简单的并查集的代码解析。

示例

下面给出两个示例。

示例 1

我们首先初始化一个并查集:

uf = UnionFindSet(10)

这个语句初始化了一个包含 10 个元素的并查集。

我们可以查看初始状态的元素和集合编号:

print(uf.father)

输出为:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

可以看到,初始时每个元素都属于自己单独的一个集合。

我们将两个元素合并:

uf.union(3, 5)

这条语句将元素 3 所在的集合和元素 5 所在的集合合并了。

我们再次查看元素和集合编号:

print(uf.father)

输出为:

[0, 1, 2, 5, 4, 5, 6, 7, 8, 9]

可以看到,元素 3 和元素 5 的集合编号变成了 5。

我们查看元素 3 和元素 5 的根节点:

print(uf.find(3))
print(uf.find(5))

输出为:

5
5

可以看到,元素 3 和元素 5 确实属于同一个集合。

示例 2

我们改变一下元素之间的关系,来看看反过来该怎么操作。

我们再次初始化一个并查集:

uf = UnionFindSet(10)

这个语句初始化了一个包含 10 个元素的并查集。

我们将两个元素合并:

uf.union(5, 3)

这条语句将元素 5 所在的集合和元素 3 所在的集合合并了。

我们再次查看元素和集合编号:

print(uf.father)

输出为:

[0, 1, 2, 3, 4, 3, 6, 7, 8, 9]

可以看到,元素 5 和元素 3 的集合编号变成了 3。

我们查看元素 5 和元素 3 的根节点:

print(uf.find(5))
print(uf.find(3))

输出为:

3
3

可以看到,元素 5 和元素 3 确实属于同一个集合。