数据结构与算法 -> 并查集

一、并查集概念

  • 并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的合并及查询问题。 它支持两种操作:
    • 查找(Find):确定某个元素处于哪个子集,单次操作时间复杂度 O(α(n)),即查询元素p和元素q是否属于同一组
    • 合并(Union):将两个子集合并成一个集合,单次操作时间复杂度 O(α(n)),即合并元素p和元素q所在的组
  • 以下是并查集的常用模板,需要熟练掌握。其中:
    • n 表示节点数
    • p 存储每个点的父节点,初始时每个点的父节点都是自己
    • size 只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
    • find(x) 函数用于查找 x 所在集合的祖宗节点
    • union(a, b) 函数用于合并 a 和 b 所在的集合

二、并查集模板

1、模板一

// 并查集类。需要维护一个数组和两个方法,find()和union()
class UnionFind {
    constructor(n) {
        this.arr = []
        // 初始默认为每个人是独立圈子,则他的父级就是他自身
        for (let i = 0; i < n; i++) {
            this.arr[i] = i
        }
    }

    // 直到arr[x] === x,停止向上搜索
    find(x) {
        let arr = this.arr
        while (arr[x] !== x) {
            x = arr[x]
        }
        return arr[x]
    }

    // 路径压缩
    union(x, y) {
        let xFather = this.find(x)
        let yFather = this.find(y)
        if (xFather !== yFather) {
            this.arr[xFather] = yFather
        }
    }
}

2、模板二

class UnionFind {
    constructor(size) {
        this.fa = []
        this.size = size
        this.init()
    }
    // 初始化 每个元素的父节点为自身
    init() {
        for(let i = 0; i < this.size; i++) {
            this.fa[i] = i
        }
    }
    // 递归找到根节点,同时进行路径压缩
    find(x) {
        if(x === this.fa[x]) {
            return x
        }
        this.fa[x] = this.find(this.fa[x])
        return this.fa[x]
    }
    // 合并 x, y 直到各自的根节点, 其中一个的指向另一个
    merge(x, y) {
        let fx = this.find(x)
        let fy = this.find(y)
        if(fx !== fy) {
            this.fa[fx] = fy
        }
    }
    // 获取集合数量
    getCount() {
        let count = 0
        for(let i = 0; i < this.size; i++) {
            if(this.fa[i] === i) {
                count++
            }
        }
        return count
    }
}

3、模板三

// 这个并查集使用了一种叫做路径压缩的优化策略,可以有效减少查找操作的时间复杂度
class UnionFind {
    constructor(n) {
        this.count = n;
        this.parent = [];
        this.rank = [];
        for (let i = 0; i < n; i++) {
            this.parent[i] = i;
            this.rank[i] = 1;
        }
    }

    // 查找元素 p 所在的集合编号
    find(p) {
        if (p !== this.parent[p]) {
            this.parent[p] = this.find(this.parent[p]);
        }
        return this.parent[p];
    }

    isConnected(p, q) {
        return this.find(p) === this.find(q);
    }

    // 将元素 p 和元素 q 所在的集合合并
    unionElements(p, q) {
        const pRoot = this.find(p);
        const qRoot = this.find(q);
        if (pRoot === qRoot) {
            return;
        }
        if (this.rank[pRoot] < this.rank[qRoot]) {
            this.parent[pRoot] = qRoot;
        } else if (this.rank[qRoot] < this.rank[pRoot]) {
            this.parent[qRoot] = pRoot;
        } else {
            this.parent[pRoot] = qRoot;
            this.rank[qRoot] += 1;
        }
    }
}

三、力扣例题

四、PDF参考资料

百度网盘:https://pan.baidu.com/s/1FzPwQKEEoSeEWFX-7A104A?pwd=hcfr

posted @ 2023-01-16 16:07  不见水星记  阅读(79)  评论(0编辑  收藏  举报