热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【经典数据结构】并查集

等价关系与等价类若对于每一对元素(a,b),a,b∈S,aRb或者为true或者为false,则称在集合S上定义关系R。如果aRb为true,那么我们说a与b有关系。等价关系(

等价关系与等价类

  若对于每一对元素(a,b),a,b∈S,a R b或者为true或者为false,则称在集合S上定义关系R。如果a R b为true,那么我们说a与b有关系。

  等价关系(equivalence relation)是满足下列三个性质的关系R:

  (1) 自反性:对于所有a∈S,a R a

  (2) 对称性:若a R b当且仅当b R a

  (3) 传递性:若a R b且b R c 则a R c

  关系“≤”不是等价关系。虽然它是自反的(即a≤a)、可传递的(即由a≤b和b≤c得出a≤c),但它不是对称的,因为a≤b不能得出b≤a。

  如果两个城市位于同一个国家,那么定义它们是由关系的。容易验证这是一个等价关系。如果能够通过公路从a旅行到b,则设a与b有关系。如果所有的道路都是双向行驶的,那么这种关系也是一个等价关系。

并查集: 

  在计算机科学中,并查集是一种树形的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示,进行快速规整。

  并查集保持一组不相交的动态集合S={S1,S2,...,Sk}。每个集合通过一个代表来识别,代表即集合中的某个成员。在某些应用中,哪一个成员被选作代表无所谓。在一些应用中,如何选择代表可能存在预先说明的规则,例如选择集合中的最小元素。

  并查集提供以下操作:

  1. Find:确定元素属于哪一个集合。不要求find操作返回任何特定的名字,而只要求当且仅当两个元素属于相同的集合时,作用在这两个元素上的find返回相同的名字。

  2. Union:将两个子集合并成同一个集合

  3. MakeSet: 用于建立单元素集合。

 

并查集的表示方法:

  1. 单链表表示

    要实现并查集数据结构,一种简单的方法是每一个集合都用一个链表来表示。每个链表的第一个对象作为它所在集合的代表。链表中的每一个对象都包含一个集合成员、一个指向包含下一个集合成员的对象的指针,以及指向代表的指针。每个链表都含head指针和tail指针,head指向链表的代表,tail指向链表中最后的对象。

  2. 并查集森林

    并查集的另一种更快的实现是用有根树表示集合树中每个节点包含一个成员,每棵树代表一个集合。在一个不相交森林中,每个成员仅指向指向它的父节点。每棵树的根包含集合的代表,并且是其自己的父节点。正如我们将要看到的那样,虽然使用这种表示的直接算法并不比使用链表表示的算法快,但通过引入两种启发式策略(“按秩合并”和“路径压缩"),我们能得到一个渐进最优的不相交集合数据结构。

    在这种表示方法中,MAKE-SET操作简单地创建一棵只有一个节点的树,Find操作通过沿着指向父节点的指针找到树的根。这一通过根节点的简单路径上所访问过的节点构成了查找路径。union操作使得一棵树指向另一棵树的根。下图所示为union操作:

    开始时每个集合含有一个元素。这些树不一定必须是二叉树,但是用二叉树表示起来要容易,因为我们需要的唯一信息就是父链(parent link)。集合的名字由根处的节点给出。由于只需要父节点的名字,因此可以假设这棵树是被非显式的存储在数组中(与二叉堆类似):数组的每个成员s[i]表示元素i的父亲。如果i是根,那么s[i]=-1.、

  

并查集森林的两种改进策略:

  1. 按秩合并(union by rank)。改进union操作的方法。这种方法的思想是在union操作中使较少节点的树的根指向具有较多节点的树的根,使得总是较小的树成为较大的树的子树。注意,这里并不显式地记录每个节点为根的子树的大小,而是采用一种易于分析的方法。对于每个节点,维护一个秩,它表示该节点高度的一个上界。在使用按秩合并策略的UNION操作中,我们可以让具有较小秩(高度)的根指向具有较大秩的根。我们初始化数组的所有项为-1。下图显示了一棵树及其对于按秩求并的实例。

  

  

 

  2. 路径压缩(path compression)。改进find操作的方法。它在查找过程中将查到节点到根的每个节点的父节点直接指向根。如下所示  

 

实现代码:

class DisjSets {
 public:
    explicit DisjSets(int numElements);

    int Find(int x);
    
    void Union(int element1, int element2); // union is key word in C++, use Union

 private:
     vector<int> s;
};

DisjSets::DisjSets(int numElements): s(numElements) {
    for (vector<int>::iterator iter = s.begin();
         iter != s.end(); ++iter) {
             *iter = -1;
    }
}

//路径压缩
int DisjSets::Find(int x)  { 
    if (s[x] <0)
        return x;
    else
        return s[x] = Find(s[x]);
}

void DisjSets::Union(int element1, int element2) {
    int root1 = Find(element1); //find root of element1
    int root2 = Find(element2); //find root of element2

    if (s[root2] < s[root1]) {
        s[root1] = root2;
    } else {
        if (s[root1] == s[root2])
            s[root1]--;
        s[root2] = root1;
    }
}

 

 

 

参考资料:

  1. 《算法导论》(第三版)

  2. 《数据结构与算法分析C++描述》(第三版)


推荐阅读
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 统一知识图谱学习和建议:更好地理解用户偏好
    本文介绍了一种将知识图谱纳入推荐系统的方法,以提高推荐的准确性和可解释性。与现有方法不同的是,本方法考虑了知识图谱的不完整性,并在知识图谱中传输关系信息,以更好地理解用户的偏好。通过大量实验,验证了本方法在推荐任务和知识图谱完成任务上的优势。 ... [详细]
author-avatar
lifetime8_797
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有