下面给出具体的 Python 实现一个简单的并查集的示例代码攻略。
什么是并查集?
并查集(Disjoint Set)是一种用于解决一些等价类问题的数据结构,它支持查询、合并等操作。所谓“等价类问题”,就是在很多元素中,有一些元素之间会互相关联,我们想要知道哪些元素之间有关联,哪些元素之间没有关联。用并查集可以快速处理这个问题。
并查集通用操作
并查集中常用的操作有以下三个:
- 初始化操作:通常是初始化每个元素自己成为一个单独的集合。
- 查找操作:即确定某个元素所属的集合。
- 合并操作:将两个元素所在的集合合并成一个集合。
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 确实属于同一个集合。