• 并查集(Union-Find Set)的学习


    什么是并查集?

    一个实现了合并与查询集合的数据结构。可以解决动态连通性一类的问题。

    那什么是动态连通性问题?

    给出一系列的对象时,让其支持下列操作:

    • 判断两个对象是否相连
    • 使两个对象相连

    这里以整数表示对象,有0-9共十个整数,当给出一个整数对(a,b)时表示将整数a和b相连(如果a、b不相连),如下图所示:

    随着整数对的输入,十个整数的连通性会发生变化,这就是动态连通性问题

    在动态连通性问题中,我们假设“相连”是一种等价关系,也就意味着他具有:

    • 自反性,p和q是相连的;
    • 对称性,如果p和q是相连的,那么q和p也是相连的;
    • 传递性,如果p和q是相连的,q和r是相连的,那么p和r也是相连的;

    在所有给出的对象中,所有相连的一组对象称为连通分量(connected component),如上图最后一行的(0,1,2,5,6,7)和(3,4,8,9)发别为两个连通分量。

    应用

    • 计算机网络:判断网络中的计算机是否可以通过已存在的连接直接通信;
    • 社交网络的的朋友关系:把朋友关系当作相连,判断两个人之间的朋友关系;
    • 计算机蕊片中晶体管的连接问题:判断蕊片中晶体管是否相连;
    • 变量名的等价性:某些编程语言(如FORTRAN)中允许声明两个等价的变量名,判断两个给定的变量名是否等价;
    • 数学集合中的元素:元素可能属于不同的集合,将元素“相连”表示将两个元素所属的集合合并成一个集合;

    设计算法

    动态连通性问题要求给出的两个点是否相连,并不要求给出具体的连接路经;至于得出连接路经的问题,可以通过深度优先搜索(DFS)算法来解决。

    在union-find算法中,要实现如何操作:

    • Find:给出的对象p属于哪个分量;
    • Connected:对象p和q是否相连;
    • Union:连接对象p和q,并将他们所属的分量合并为一个分量;

    对应api如下:

    • UF(int n),以整数标识(0到N-1)初始化N个触点;
    • void union(int p,int q),在p与q之间添加一条连接;
    • int find(int p),返回p所在分量的标识符;
    • boolean connected(int p,int q),判断q与p是否相连;
    • int count();所有连通分量的数量;

    代码实现

    • 快速查找

    既然用分量标识符代表一个分量,那么直接使同一分量中的所有触点的分量标识符相同即可,在判断两个触点的连通情况时只需判断其分量标识符是否相同,即id[q]==id[p]。那么在实现union()方法时,首先判断q,p是否属于同一分量,如果不是,则需要合并两者所代表的分量。根据同一分量中所有触点的分量标识符相同的原则,遍历整个数组,将所有与id[p]相等的元素值变为id[q]。这样的实现称为quick-find(快速查找)算法。此算法的时间复杂度为平方级别的,当数组较大时,运行效率就较低。

    • 快速合并

     在quick-find算法中,find()的速度是很快,而union()操作在需要合并分量时要遍历整个数组而效率较低。在合并分量时,需要关注的并不是所有的触点,只是与元素p同属一个分量的触点才需被访问,因此,将同一分量的触点组织结合起来,当需要修改时直接访问该分量中的触点可以减少无关触点的访问。

    同样是以触点为索引的id组数,但其中保存的值不再是相同的分量标识符,而是同一个分量中另一个触点(可能是自已)的名称。而实现find()方法时,从给定的触点开始,再同这个触点链接到第三个触点,直到根触点--链接指向自已的触点,那么这个根触点就代表了这个分量。当判断两个触点是否相连时,沿着各自的链接得到根触点后比较根触点是否相同即可。

    在实现union()方法时,为了能保证合并后两个分量的所有触点的根触点相同,直接到其中一个分量的根触点链接到另一个分量的根触点上就可以快速的合并两个分量。因为这个算法称为quick-union(快速合并)算法

    从上图的示意图可以看出,quick-union算法是采用树结构来采代quick-find算法中使用的数组来来组织元素,实现高效的查找与修改。

    quick-union算法的优化 

    leetcode相关题目

    684. Redundant Connection

    547

    737

  • 相关阅读:
    localStorage和sessionStorage区别(包括同源的定义)
    跨域问题实践总结! 上(JSONP/document.domain/window.name)
    7月11日计划
    图形验证码知识点整理 Object.prototype.toString.call()等
    学习日报 7-10(验证码)
    Mysql安装与主从配置
    windows service编程
    Entity Framework——常见报错总结
    Entity Framework——读写分离
    Entity Framework——执行sql语句
  • 原文地址:https://www.cnblogs.com/johnnyzhao/p/12275155.html
Copyright © 2020-2023  润新知