算法基础进阶部分-并查集

该博客介绍了如何利用并查集数据结构解决岛屿数量统计问题。首先,通过遍历二维数组并进行‘感染’操作来标记岛屿,然后利用并查集的查找和联合操作判断元素是否属于同一集合,从而计算岛屿数量。同时,展示了并查集的实现细节,包括查找代表元素、判断元素是否属于同一集合以及合并集合的方法。
摘要由CSDN通过智能技术生成
/**
 * 并查集
 */
public class BingChaJi {

    //岛
    public static int countIslands(int[][] m) {
        //如果二维数组二维为空返回
        if (m == null || m[0] == null) {
            return 0;
        }
        //N为二维数组的行数
        int N = m.length;
        //M为二维数组的列数
        int M = m[0].length;
        int res = 0;
        //外层循环行
        for (int i = 0; i < N; i++) {
//            内层循环列
            for (int j = 0; j < M; j++) {
                //在从上往下循环列的时候碰到了1就进行感染操作
                if (m[i][j] == 1) {
                    //记录岛的数量
                    res++;
//                    感染操作
                    infect(m, i, j, N, M);
                }
            }
        }
        return res;
    }

    private static void infect(int[][] m, int i, int j, int N, int M) {
        //如果当前的坐标越界了或者不为1那么就返回
        if (i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1) {
            return;
        }
        //i,j没越界,并且当前位置值是1 就直接把当前的1感染成2
        m[i][j] = 2;
        //下边进行感染操作
        infect(m, i + 1, j, N, M);
//        上边进行感染操作
        infect(m, i - 1, j, N, M);
        //右边进行感染操作
        infect(m, i, j + 1, N, M);
        //左边进行感染操作
        infect(m, i, j - 1, N, M);

    }

    //并查集
    public static class Element<V> {
        public V value;

        public Element(V value) {
            this.value = value;
        }
    }

    public static class UnionFindSet<V> {
        public HashMap<V, Element> elementMap;
        //key 某个元素 value 该元素的父
        public HashMap<Element<V>, Element<V>> fatherMap;
        //key 某个集合的代表元素,value 该集合的大小
        public HashMap<Element<V>, Integer> sizeMap;

        public UnionFindSet(List<V> list) {
            elementMap = new HashMap<>();
            fatherMap = new HashMap<>();
            sizeMap = new HashMap<>();
            for (V value : list) {
                Element<V> element = new Element<V>(value);
                elementMap.put(value, element);
                fatherMap.put(element, element);
                sizeMap.put(element, 1);
            }
        }

        //给定应该ele,往上一直找,把代表元素返回
        private Element<V> findHead(Element<V> element) {
            Stack<Element<V>> path = new Stack<>();
            while (element != fatherMap.get(element)) {
                path.push(element);
                element = fatherMap.get(element);
            }
            while (!path.isEmpty()) {
                fatherMap.put(path.pop(), element);
            }
            return element;
        }

        public boolean isSameSet(V a, V b) {
            if (elementMap.containsKey(a) && elementMap.containsKey(b)) {
                return findHead(elementMap.get(a)) == findHead(elementMap.get(b));
            }
            return false;
        }

        public void union(V a, V b) {
            if (elementMap.containsKey(a) && elementMap.containsKey(b)) {
                Element<V> aF = findHead(elementMap.get(a));
                Element<V> bF = findHead(elementMap.get(b));
                if (aF != bF) {
                    Element<V> big = sizeMap.get(aF) >= sizeMap.get(bF) ? aF : bF;
                    Element<V> small = big == aF ? bF : aF;
                    fatherMap.put(small, big);
                    sizeMap.put(big, sizeMap.get(aF) + sizeMap.get(bF));
                    sizeMap.remove(small);
                }
            }
        }

        public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
            list.add(6);
            UnionFindSet<Integer> set = new UnionFindSet(list);

            set.union(1, 2);
            boolean sameSet = set.isSameSet(1, 2);
            System.out.println(sameSet);


        }
    }

    public static void main(String[] args) {
        int[][] arr =
                {{0, 0, 0, 0, 0, 0, 0},
                        {0, 1, 1, 0, 0, 0, 0},
                        {0, 1, 0, 0, 0, 0, 0},
                        {0, 0, 0, 1, 1, 1, 1},
                        {0, 0, 0, 1, 0, 0, 1},
                        {0, 0, 0, 0, 0, 0, 0},
                        {0, 1, 1, 1, 0, 0, 0}};
        System.out.println("感染前数组的样子:");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
        int i1 = countIslands(arr);
        System.out.println("岛的个数是:" + i1);
        System.out.println("感染后的数组的样子:");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值