并查集讲解

什么是并查集


并查集讲解_第1张图片

并查集是一种数据结构,用来快速查询集合元素之间是否有关系,是否有关系判断标准是是否有相同的根节点

举一个恰当的例子,要判断图谱中的两个元素是否有关系,如果使用常规的查询方法,时间复杂度比较大,使用并查集就是用来优化这种情况,使得判断两个元素是否有关联可以达到O(1)

普通查询思路

按照上图,要判断11和4是否有关系,我们可以一直向上追溯父亲节点,11的上层是9,9的上层节点是0,那么11的祖父节点就是0。同理,追溯4的祖父节点是0,那么这两个节点的祖父节点都是0,则两个节点有关系

知道了思路,抽象出代码就很简单了,现在要解决的有两个问题,使用非递归,从下往上进行追溯,什么时候是截止条件呢,可以让0号节点的父节点指向自己。第二个问题就是如何存储这样一个结构,由于每个节点只需要用到父节点,可以使用map来进行存储,代码如下:

        //找a的祖父节点
		int father = map.get(a);
        while (father != map.get(father)) {
            father = map.get(father);
        }

O(1)优化

按照上面的思路一级一级的追溯,很明显时间复杂度是O(n),如何进行优化呢

举个例子,当查询过一遍4的祖父节点是0的时候,我们就可以直接更新4的父节点是0,后续再使用到4的时候,就不会做重新劳动了,我们可以继续思考,既然用到4了,我们可以直接将4开始往上所有的路径节点都直接更新

所以,整个思路分为两步,第一步还是先找到顶级根节点,第二步从当前节点开始往上,依次更新父节点

		//找a的祖父节点
		int father = map.get(a);
        while (father != map.get(father)) {
            father = map.get(father);
        }

		//从当前节点往上更新父节点
		int temp = -1;
		int fa = map.get(a);
		while(fa != map.get(fa)) {
            //temp保存原父节点,防止更新后丢失
            temp = map.get(fa);
            map.put(fa,father);
            fa = temp;
        }

数据结构

根据上面的思路,就可以整理出来该数据结构

class UnionFind {
    HashMap<Integer,Integer> map;

    public UnionFind() {
        map = new HashMap<>();
    }

    //初始化所有节点,每个节点的父节点都指向自己
    public void find0() {
        //... 这里根据情况来写,遍历每个父节点指向自己
    }

    public int find(int num) {
        int father = map.get(num);
        while (father != map.get(father)) {
            father = map.get(father);
        }

        //从当前节点往上更新父节点
        int temp = -1;
        int fa = map.get(num);
        while(fa != map.get(fa)) {
            //temp保存原父节点,防止更新后丢失
            temp = map.get(fa);
            map.put(fa,father);
            fa = temp;
        }

        return father;
    }
    
    //合并
    public void union(int a,int b) {
        int fa_a = find(a);
        int fa_b = find(b);
        if(fa_a != fa_b) {
            map.put(fa_a,fa_b);
        }
    }
}

你可能感兴趣的:(算法与数据结构,并查集,数据结构)