Python 并查集(Disjoint Set)及路径压缩

并查集(Disjoint Set)是一种用于解决合并(Union)和查找(Find)问题的数据结构。在计算机科学中,常用于解决图的连通性问题,如求解最小生成树、判断图是否连通等。本文将介绍 Python 中的并查集数据结构,并讲解路径压缩算法的原理和实现。

1. 并查集的基本概念

并查集将每个元素看作一个节点,并使用树的结构来表示集合。每个节点都有一个指向父节点的指针,根节点指针指向自身。每个集合都由一个根节点来代表。在初始状态下,每个节点都是一个独立的集合。

并查集的两个基本操作如下:

  • 合并(Union):将两个集合合并为一个集合。
  • 查找(Find):查找元素所在的集合。

合并操作通常通过将一个集合的根节点指向另一个集合的根节点来实现。查找操作则通过递归查找根节点来确定节点所属的集合。

2. 并查集的实现

在 Python 中,我们可以使用一个列表来实现并查集。列表的索引表示节点的索引,而列表的值表示该节点的父节点的索引。根节点的父节点为-1。

下面是一个简单的并查集的实现代码:

class DisjointSet:
    def __init__(self, size):
        self.parent = [-1] * size

    def find(self, index):
        if self.parent[index] < 0:
            return index
        else:
            # 路径压缩
            self.parent[index] = self.find(self.parent[index])
            return self.parent[index]

    def union(self, index1, index2):
        root1 = self.find(index1)
        root2 = self.find(index2)
        if root1 != root2:
            if self.parent[root1] < self.parent[root2]:
                self.parent[root2] = root1
            else:
                if self.parent[root1] == self.parent[root2]:
                    self.parent[root2] -= 1
                self.parent[root1] = root2

在这个实现中,我们使用 parent 列表来存储每个节点的父节点。find 方法用于查找节点所属的集合,并进行路径压缩,将节点的父节点直接指向根节点,加速后续查找操作。union 方法用于合并两个集合,首先找到两个集合的根节点,并将其中一个根节点的父节点指向另一个根节点。

3. 路径压缩

路径压缩是并查集中的一种优化技巧,它可以减少查找操作的时间复杂度。路径压缩的基本思想是将节点的父节点直接指向根节点,减少后续查找操作中的递归次数。

路径压缩可以通过递归调用 find 方法实现。在 find 方法中,当找到根节点时,将节点的父节点指向根节点。这样,在后续查找操作中,就可以通过一次访问直接找到根节点,大大减少了递归的深度。

4. 序列图

下面是一个使用序列图(Sequence Diagram)表示并查集的合并和查找操作的示例:

sequenceDiagram
    participant A as Node A
    participant B as Node B
    participant C as Node C
    A->>B: Union
    B->>C: Union
    A->>C: Find

在示例中,节点 A 和节点 B 先进行合并操作,然后节点 B 和节点 C 进行合并操作。最后,节点 A 和节点 C 进行查找操作,确认它们是否属于同一个集合。

5. 总结

本文介绍了 Python 中的并查集数据结构及路径压缩的原理和实现。并查集是一种用于解决合并和查找问题的数据结构,常用于解决图的连