用java写数据结构作业——7.2堆并查集哈夫曼树二

数据结构第9周作业——堆并查集哈夫曼树二

7-2 并查集【模板】 (60分)
给出一个并查集,请完成合并和查询操作。
输入格式:
第一行包含两个整数N、M,表示共有N个元素和M个操作。
接下来M行,每行包含三个整数Z​i​​、X​i​​、Y​i​​。
当Z​i​​=1时,将X​i​​与Y​i​​所在的集合合并。
当Z​i​​=2时,输出X​i​​与Y​i​​是否在同一集合内,是的话输出Y;否则的话输出N。
输出格式:
对于每一个Z​i​​=2的操作,对应一行输出,每行包含一个大写字母,为Y或者N。
输入样例:
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

输出样例:
N
Y
N
Y

数据规模:
对于30%的数据,N<=10,M<=20;
对于70%的数据,N<=100,M<=1000;
对于100%的数据,N<=10000,M<=200000。

解决思路:通过审题可以发现题目要求对多个集合进行合并和查询,开始我想到的是用为每个数建立一个set,如要合并就将其中一个set中的值加入集合并将其销毁,但是考虑到题目中测试数据过于庞大,创建多个对象显然会耗费许多内存。抓住开始单个元素便是一个集合的特点,于是初期先用一个数组来存储数据,等有操作命令时再来创建set集合,而这些set集合由一个list来维护。

这时候我们需要有两个方法findTwo(查询)和merge(合并)以及一个私有方法findOne(查找数所在的集合)

Object FindOne(int a)
1.首先在数组中查找,找到则说明不在一起
2.若未找到则到list中遍历查找,返回所在集合(若在数组中则返回null)
注意:不必遍历,因为每个数组的下标即为它的值

Void findTwo(int a,int b)
1.调用findOne查找a所在集合
2.在集合中查找是否存在b
3.若有则输出打印Y,没有则N

Void merge(int a ,int b)
1.用私有方法findOne查询a,b所在集合
2.合并

import java.util.*;


public class Main {
    //初始数组
    public static int[] array;
    //维护set集合的list
    public static List<Set<Integer>> setArray=new ArrayList<>();

    public static void main(String[] args) {
        //提前声明,避免在循环中声明占内存
        int z,a,b;
        //创建一个文本扫描器检测键盘输入
        Scanner scanner=new Scanner(System.in);
        //N个元素
        int N=scanner.nextInt();
        //M个操作
        int M=scanner.nextInt();
        //初始化array,确保下标即为对应的值
        array=new int[N+1];
        for (int i=0;i<N+1;i++){
            array[i]=i;
        }
        //循环操作
        for (int i=0;i<M;i++){
            z=scanner.nextInt();
            a=scanner.nextInt();
            b=scanner.nextInt();
            if (z==1){
                merge(a,b);
            }else if (z==2){
                findTwo(a,b);
            }
        }

    }


    /**
     * 1.首先在数组中查找,找到则说明不在一起
     * 2.若未找到则到list中遍历查找,返回所在集合(若在数组中则返回null)
     * 注意:不必遍历,因为每个数组的下标即为它的值
     * @param a
     * @return
     */
    private static Set<Integer> findOne(int a){
        if (array[a]!=0){
            return null;
        }
        //在维护set集合的数组中遍历
        for (Set<Integer> set:setArray){
            //调用contain方法,若存在则返回该集合
            if (set.contains(a)){
                return set;
            }
        }
        //这道题不可能执行到这步,除非系统想搞我们!当然我们也不怕
        return null;
    }

    /**
     * 1.调用findOne查找a所在集合
     * 2.在集合中查找是否存在b
     * 3.若有则输出打印Y,没有则N
     * @param a
     * @param b
     */
    public static void findTwo(int a,int b){
        Set<Integer>set=findOne(a);
        if (set==null){
            //集合为空时,即a在数组中时输出N
            System.out.println("N");
        }else if (set.contains(b)){
            System.out.println("Y");
        }else{
            //不包含时输出N
            System.out.println("N");
        }
    }

    /**
     * 1.用私有方法findOne查询a,b所在集合
     * 2.合并
     * @param a
     * @param b
     */
    public static void merge(int a,int b){
        Set<Integer> set1=findOne(a);
        Set<Integer> set2=findOne(b);
        //分别讨论几种情况
        if (set1==null&&set2!=null){
            set2.add(a);
            //原来数组的值清0
            array[a]=0;
        }else if (set1!=null&&set2==null){
            set1.add(b);
            array[b]=0;
        }else if (set1==null&&set2==null){
            //此时需要创建一个set集合,并清0
            Set<Integer> set=new HashSet<Integer>();
            set.add(a);
            set.add(b);
            //别忘了加入list集合,粗心的我就忘了!汗。。。
            setArray.add(set);
            array[a]=0;
            array[b]=0;
        }else {
            //判断两个集合是否相等
            if (set1!=set2){
                //确保小的集合加入大的集合
                if (set1.size()<set2.size()){
                    set2.addAll(set1);
                    //把多余的set集合清出list,粗心的我又忘了......
                    setArray.remove(set1);
                }else {
                    set1.addAll(set2);
                    setArray.remove(set2);
                }
            }
        }

    }
}

记录点滴,乐于分享,转载请注明出处

以梦为马,不负人生韶华,我们追梦在路上!

愿与君共勉!

猜你喜欢

转载自blog.csdn.net/qq_46101869/article/details/105494026