15.6:并查集,用两个数组实现

package algorithmbasic.class15;

import java.io.*;

// 这个文件课上没有讲
// 原理和课上讲的完全一样
// 最大的区别就是这个文件实现的并查集是用数组结构,而不是map结构
// 请务必理解这个文件的实现,而且还提供了测试链接
// 提交如下的code,并把"Code06_UnionFind"这个类名改成"Main"
// 在测试链接里可以直接通过
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 测试链接 : https://www.nowcoder.com/questionTerminal/e7ed657974934a30b2010046536a5372
public class UnionFind2 {
    
    
    /**
     * 属性
     */
    public static int MAX = 100001;
    //father数组:下标是集合元素,数组内容是father。
    public static int[] father;
    //size数组:下标是头部集合的元素,数组内容是这个集合的元素个数。
    public static int[] size;
    //help数组:主要是进行优化用的,里面存储着寻找祖先节点是经过的节点,当找到祖先节点后,将途径的节点直接连接到祖先节点上,
    //从而降低了查找的长度。
    public static int[] help;

    /**
     * init方法
     * 并查集的初始化。
     */
    public static void init(int n) {
    
    
        father = new int[MAX];
        size = new int[MAX];
        help = new int[MAX];
        for (int i = 0; i < n; i++) {
    
    
            father[i] = i;
            size[i] = 1;
        }
    }


    /**
     * findAncestor方法
     * 传入一个元素,找这个元素的祖先。
     */
    public static int findAncestor(int x) {
    
    
        int j = 0;
        while (x != father[x]) {
    
    
            //将途径的节点放入到help辅助数组中。
            help[j++] = x;
            x = father[x];
        }
        // x == father[x]现在的x就是祖先节点。
        //将途径的节点直接连到祖先节点上,从而降低了下次查找的长度。
        j--;
        while (j >= 0) {
    
    
            father[help[j]] = x;
            j--;
        }
        return x;
    }

    /**
     * isSameSet方法
     * 查询两个元素是否是在同一个集合
     */
    public static boolean isSameSet(int x, int y) {
    
    
        //找两个元素的祖先。
        return findAncestor(x) == findAncestor(y);
    }

    /**
     * union方法
     * 将两个元素所在的集合进行合并
     */
    public static void union(int x, int y) {
    
    
        //找到元素x所在集合的祖先。
        int fatherX = findAncestor(x);
        //找到元素y所在集合的祖先。
        int fatehrY = findAncestor(y);
        //找到fatherX所在集合的元素个数
        int nubX = size[fatherX];
        //找到fatherY所在集合的元素个数
        int nubY = size[fatehrY];
        //big指向的是元素个数比较多的头部节点。
        //small指向的是元素个数比较少的头部节点。
        int big = nubX > nubY ? fatherX : fatehrY;
        int small = big == nubX ? fatehrY : fatherX;
        //将集合元素小的挂在集合元素多的祖先节点下。
        size[big] = size[big] + size[small];
        size[small] = 0;
        father[small] = big;
    }


    public static void main(String[] args) throws IOException {
    
    
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StreamTokenizer in = new StreamTokenizer(br);
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        while (in.nextToken() != StreamTokenizer.TT_EOF) {
    
    
            int n = (int) in.nval;
            init(n);
            in.nextToken();
            int m = (int) in.nval;
            for (int i = 0; i < m; i++) {
    
    
                in.nextToken();
                int op = (int) in.nval;
                in.nextToken();
                int x = (int) in.nval;
                in.nextToken();
                int y = (int) in.nval;
                if (op == 1) {
    
    
                    out.println(isSameSet(x, y) ? "Yes" : "No");
                    out.flush();
                } else {
    
    
                    union(x, y);
                }
            }
        }
    }
}

注意使用并查集合并一次只能合并两个。

并且使用并查集并不会改变原容器中数据的顺序与状态。

猜你喜欢

转载自blog.csdn.net/SCR1209/article/details/130986424