zoukankan      html  css  js  c++  java
  • 【并查集学习笔记】------迟来的总结

    定义

    并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。
    并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。---百度
    并查集,顾名思义,也就是支持 “并”, “查”, “集”的一种数据结构,可以合并,查询以及集合。是一种极为重要的算法,在各个方面均有应用。
    

    实现并查集

    并查集一般支持两个操作:

    • 查找祖先
    • 合并集合
      如下:
      首先,我们需要一个 fa 数组,把 fa[i] 初始化为 i。也就是最开始的时候,他的爸爸就是他自己。
    for (int i = 1; i <= n; i++) fa[i] = i;
    

    然后,我们还要一个 Find 函数用于查找他的祖先,具体的原理就是递归实现。
    注 : 我们最好不要用 find,因为它好像是一个关键字还是函数之类的东西,并且单驼峰命名也是一个好习惯

    int Find (x) {
    	if (fa[x] != x) return Find (fa[x]);
        //因为我们可以知道,一个集合的祖先的父亲肯定是没有被改变过的,也就是我们初始化时的他自己,如果这个节点的父亲还不是祖先,那么我们就要寻找他父亲的父亲(一辈一辈往上找)
    	else return fa[x]; //否则我们就返回他自己(边界)(此处返回 x 是一样的)
    }
    

    我们就会发现,万一有一个集合是下面的样子呢?

    那么我们就会发现,我们的每一次访问都可能会浪费掉很多时间,又因为我们每一次查找的目的都是为了查找一个点的祖先,所以我们可以在查找 x 的祖先的时候,就直接把他的父亲的值直接赋成他的祖先,也就是:

    int Find (x) {
    	if (fa[x] != x) return fa[x] = Find (fa[x]);
    	else return fa[x]; 
    }
    

    没错,就是上面的代码,只是变了一点点而已,但他却可以大大优化你的时间复杂度(大多数题都会卡你),并且他还有一个很高大上的名字 : 路径压缩

    我们还需要一个 Merge 函数来进行合并两个数,原理就附在代码上

    bool Merge (int x, int y) {//布尔是因为大多数题都还有其他操作,随机应变咯
    	x = Find (x);
    	y = Find (y);//查找各自的祖先
    	if (x == y) return 0;//假如他们就在同一个集合之中,那么不用管他们
    	fa[y] = x;//把 y 的父亲修改成 x (因为大多数题目中,x < y)
    	return 1;
    }
    
  • 相关阅读:
    164.Maximum Gap
    163.Missing Ranges
    162.Find Peak Element
    161.One Edit Distance
    160.Intersection of Two Linked Lists
    7.5爬取猫眼Top100电影名单
    7.5文件操作
    7.4文件操作(1)
    7.4一个失败的网易云爬虫,
    7.3数据结构(1)
  • 原文地址:https://www.cnblogs.com/cqbzyanglin/p/13537944.html
Copyright © 2011-2022 走看看