图论——并查集

并查集

图论——并查集_第1张图片
图论——并查集_第2张图片

分析

  1. 我们用一个数组f去建立关系,可以理解为保存前驱结点,f[2]=1:说明2的祖先是1;
  2. 然后我们首先要初始化这个f数组,我们让每个结点的祖先都先指向自己,然后通过union去合并,存在关系的数据对;
  3. 建立好关系后,最后我们通过find函数去查询所想要查找的结点关系;

当查找得结点的祖先为自己本身,就查找到了最终位置,也就是递归出口;

static int find(int i) {//查到i的祖先
        if (f[i] == i)//递归出口,到达了祖先
            return i;
        return find(f[i]);//不断往上查找祖先
    }

可以对查找进行优化,就是路径压缩,通过递归的回溯时候;不断将每个结点的祖先直接设置为根节点;

static int find(int i) {
        if (f[i] == i)
            return i;
        //在递归返回的时候,不断将根节点作为每一个结点的父亲
        return f[i] = find(f[i]);//i的祖先为 查找i的祖先
    }

  1. 先利用find函数去查找这两个节点的祖先,然后将他们的祖先建立起关系;
  2. 让a的祖先的指向b:f[a] = f[b],或者让b的祖先指向a:f[b]=f[a];这两种方式都可以,毕竟只要建立起联系后,在后续查询操作可以查到具有公共祖先即可说明所查找的两个结点存在关系
//并
    static void union(int i, int j) {
        //查找这两个点的祖先,让他们直接产生联系
        int a = find(i);
        int b = find(j);
        f[a] = f[b];//让a的祖先指向b
        //f[b]=f[a];这样也可以,都行
    }

你可能感兴趣的:(#,并查集,java)