zl程序教程

您现在的位置是:首页 >  其它

当前栏目

6.7 并查集

查集 6.7
2023-09-14 09:06:54 时间

基本概念

  并查集Disjoint Set可能是最简单的数据结构了。它的用途不是很广,主要用于最小生成树的Kruskal算法、Boruvka算法、图的查环等。并查集这个中文翻译不是很恰当,Disjoint Set,在数学上是没有共同元素的集合。在数据结构中是指互相没有公共元素的一群集合,并且要支持创建、合并、查找三种操作。
  从抽象定义上看,没有要求用森林实现。但是为了性能等方面考虑,最好是用森林实现。合并时,是一棵树成为另一棵树的parent节点。为了树的平衡,减少树查询层数,用一个rank字段来记录层数,并且按照层数来合并。搜索使用递归方法。
  并查集Disjoint Set是一个森林,包含了很多棵树,每棵树叫Handler。

基本操作

  创建make set,指的是传入一个元素,返回一个只含一个元素的并查集。
  查找find set,传入元素,返回包含该元素的并查集。
  合并union set,将两个集合合并。
  路径压缩path compression technique,在查找时,将指向parent的长链缩短成两级,方便以后再次查询。

Java实现

因为逻辑比较简单,所以就直接贴java代码了。代码中包含了测试方法。

public class DisjointSet<T> {
    private T value;
    private DisjointSet<T> parent;
    private int rank;

    public DisjointSet(T value) {
        this.value = value;
        parent = this;
    }

    public void union(DisjointSet<T> other) {
        this.link(other);
    }

    private void link(DisjointSet<T> other) {
        if (this.rank > other.rank) {
            other.parent = this;
        } else {
            this.parent = other;
            if (this.rank == other.rank) {
                other.rank = this.rank + 1;
            }
        }
    }

    public DisjointSet<T> findSet() {
        if (this != this.parent) {
            this.parent = parent.findSet();
        }
        return parent;
    }

    @Override
    public String toString() {
        return value.toString();
    }

    public static void main(String[] args) {
        final DisjointSet<Integer> set1 = new DisjointSet<>(3);
        final DisjointSet<Integer> set2 = new DisjointSet<>(5);
        final DisjointSet<Integer> set3 = new DisjointSet<>(7);
        set1.union(set2);
        System.out.println(set1.findSet());
        set1.union(set3);
        System.out.println(set2.findSet());
    }
}

Python实现

# 并查集
class Handler:

    def __init__(self, vertex):
        self.__vertex = vertex
        self.__parent = self
        self.__rank = 0

    @property
    def vertex(self):
        return self.__vertex

    @property
    def parent(self):
        return self.__parent

    @parent.setter
    def parent(self, value):
        self.__parent = value

    @property
    def rank(self):
        return self.__rank

    @rank.setter
    def rank(self, value):
        self.__rank = value

    def union(self, other):
        if self.__rank > other.__rank:
            other.__parent = self
        else:
            self.__parent = other
            if self.__rank == other.__rank:
                other.__rank = other.__rank + 1

    def find(self):
        x = self
        if x != x.__parent:
            x.__parent = x.parent.find()
        return x.__parent

class DisjointSet:
    # 对于每一个item,应该找到属于它的最小的集合

    def __init__(self, n):
        self.__forest = [None] * n

    def make_set(self, item):
        h = Handler(item)
        self.__forest[item] = h
        return h

    def union_set(self, x, y):
        self.find_set(x).union(self.find_set(y))

    def find_set(self, item):
        return self.__forest[item].find()