高阶数据结构之-并查集

简介: 高阶数据结构之-并查集

并查集原理

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中

并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题,常常在使用中以森林来表示

适合于描述这类问题的抽象数据类型称为并查集(union-findset)


小例子-编号和人

如果我们想让编号和人构成关系, 即可以通过编号找到对应的人,也可以通过人找到对应的编号怎么做?

template<classT>  

classUnionFindSet

{

public:

   UnionFindSet(constT*a, size_tn)  

   {

       for (inti=0; i<n; i++)

       {

           _a.push_back(a[i]);

           _indexMap[a[i]] =i;

       }

   }

private:

   vector<T>_a;  //编号找人  下标对应的就是人名

   map<T, int>_indexMap;//人找编号  key:人名   value:编号

};

#include"UnionFind.h"

intmain()

{

   stringa[] = { "张三","李四","王五" };

   UnionFindSet<string>ufs(a, 3);

   return0;

}


并查集的实现

#include

#include

classUnionFindSet

{

public:

   UnionFindSet(size_tn);

   size_tFindRoot(intx);

   voidUnion(intx1, intx2);

   boolInset(intx1,intx2);

   size_tSetCount();

private:

   std::vector<int>_set;

};


首先我们要知道如下规则:

  1. 数组的下标对应集合中元素的编号
  2. 数组中的值如果为负数,负号代表根,数字代表该集合中元素个数
  3. 数组中的值如果为非负数,代表该元素双亲在数组中的下标

例如:


基本结构

classUnionFindSet

{

private:

   std::vector<int>_set;

};

构造函数

最初每个元素各自构成一个集合, 初始状态就是-1,表示size个集合

UnionFindSet(intsize)

   :_set(size, -1)//size个元素都最初初始化为-1

   {}


查找根节点

返回根节点所在下标

//如果_set[x]是负数,那么x就是某个集合的根

//如果_set[x]不是负数,那么x的父亲节点就是_set[x]值对应的位置

size_tFindRoot(intx)

{

   while (_set[x] >=0)

   {

       x=_set[x];

   }

   //来到这,_set[x] <0, 此时x就是根节点

   returnx;

}


路径压缩技巧

路径压缩实际上是在数据量太大的时候,访问一些数据可能在位于叶子位置,导致访问的效率不高

本质上我们查找的代表节点的时候,可以对该路径上的节点进行路径压缩

注意:最好不要用递归的时候进行路径压缩,因为路径深可能导致栈溢出


做法:

1)先找到当前路径节点的代表节点

2)然后从当前位置_set[x]开始的节点,沿途的节点的父亲位置都改为代表节点的位置

  只需要根据下标关系往上迭代即可x节点的父亲位置就是_set[x]位置

注意:要提前保存x节点的父亲节点位置,因为更改当前位置的父亲节点, 会丢失以前的父亲节点

size_tFindRoot(intx)

{

   introot=x;

   while (_set[root] >=0)

   {

       root=_set[root];

   }

   //此时root就是x这条路径的头节点(代表节点)

   //把沿途的节点的父亲都改为root

   while (_set[x] >=0)

   {

       intparent=_set[x];//先保存x节点的父节点位置

       _set[x] =root;//将x节点的父亲位置改为root位置

       x=parent;//往上迭代

   }

   returnroot;

}


合并集合


这里选择合并到x2所在的集合合并到x1所在的集合

voidUnion(intx1, intx2)

{

   //找到x1和x2的代表节点(根节点)

   size_troot1=FindRoot(x1);

   size_troot2=FindRoot(x2);

   //两个节点不在一个集合才合并

   //把root2合并到root1所在集合

   if (root1!=root2)

   {

       _set[root1] +=_set[root2];//root2所在集合的元素累加到root1所在集合

       _set[root2] =root1; //root2的父亲变为root1

   }

}

如果我们希望是小集合合并到大集合呢?  即元素少的集合合并到元素多的集合

路径压缩技巧

两颗树合并的时候,节点少的数往节点多的树合并

目的:为了使节点层数增多的节点相对减少


做法:

1)判断哪颗树的节点更多, 让root1变为是较大的集合, root2往root1合并

如何判断呢? 因为root1和root2是根,_set[root]的值是负数,代表该集合的元素个数, _set[root]值越大,集合元素个数越少

//x1和x2合并 ->本质是代表节点(根节点)合并

voidUnion(intx1, intx2)

{

   //找到x1和x2的代表节点(根节点)

   size_troot1=FindRoot(x1);

   size_troot2=FindRoot(x2);

   //我们让root1的集合是大集合,小集合合并到大集合中

   //因为root1和root2是根,所以_set[root]的值为负数,代表集合的元素个数,值越小,元素越多

   if (_set[root1] >_set[root2]) //说明root2集合元素多

   {

       ::swap(root1, root2);

   }

   //两个节点不在一个集合才合并

   if (root1!=root2)

   {

       _set[root1] +=_set[root2];//root2所在集合的元素累加到root1所在集合

       _set[root2] =root1; //root2的父亲变为root1

   }

}


求集合个数

遍历_set,查看有多少元素是负数,就代表有多少个根节点, 即有多少个集合

size_tSetCount()

{

   size_tcount=0;

   for (autoe : _set)

   {

       if (e<0) count++;

   }

   returncount;

}


判断两个元素是否在同一个集合

只需要判断两个元素的代表节点的位置是否相同即可

boolInset(intx1,intx2)

{

   returnFindRoot(x1) ==FindRoot(x2);

}



相关文章
|
11天前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
2月前
|
算法 程序员 图形学
脑洞大开!Python并查集:用最简单的方式,解决最复杂的数据结构问题!
【7月更文挑战第17天】并查集,数据结构明星,处理不相交集合合并与查询。Python实现核心操作:查找与合并。路径压缩优化查找,按秩合并保持平衡。实战应用如图连通性判断,算法竞赛利器。掌握并查集,解锁复杂问题简单解法,照亮编程之旅!
43 10
|
2月前
|
Python
告别低效!Python并查集:数据结构界的超级英雄,拯救你的编程人生!
【7月更文挑战第18天】并查集,数据结构超级英雄,用于不相交集合的合并与查询。Python实现包括初始化、查找根节点和合并操作。应用广泛,如社交网络分析、图论问题、集合划分等。示例代码展示了解决岛屿数量问题,统计连通的“1”单元格数。掌握并查集,提升编程效率,解决复杂问题。
42 6
|
2月前
|
存储 Python
震惊!Python并查集:解锁数据结构新姿势,让你从菜鸟秒变大神!
【7月更文挑战第18天】并查集,一种处理不相交集合的树形数据结构,支持Union(合并)和Find(查询)操作。Python实现中,用字典存储元素及其父节点,初始时每个元素为根。通过路径压缩提高效率。应用包括网络连通性判断、动态连通性检测和集合操作。掌握并查集,提升编程技能,解决复杂问题。开始探索,成为数据结构大师!
31 5
|
2月前
|
Python
逆天改命!掌握Python并查集,数据结构难题从此不再是你的痛!
【7月更文挑战第18天】并查集,一种神器数据结构,用于处理不相交集合合并与查询,解决网络连通性等难题。Python实现常通过记录元素父节点
31 4
|
2月前
|
算法 数据挖掘 计算机视觉
Python并查集实战宝典:从入门到精通,让你的数据结构技能无懈可击!
【7月更文挑战第17天】并查集,如同瑞士军刀,是解决元素分组问题的利器,应用于好友关系、像素聚类、碰撞检测和连通性分析等场景。本文从基础到实战,介绍并查集的初始化、查找与路径压缩、按秩合并,以及在Kruskal算法中的应用。通过并查集,实现高效动态集合操作,对比哈希表和平衡树,其在合并与查找上的性能尤为突出。学习并查集,提升算法解决复杂问题的能力。
63 5
|
2月前
|
存储 算法 程序员
庆祝吧!掌握Python并查集,数据结构难题将不再是你的拦路虎!
【7月更文挑战第17天】并查集,一种数据结构,用于不相交集合的合并与查询,尤其适合解决图的连通性问题。通过Python实现,使用列表存储元素的父节点以判断集合关系。基本操作包括查找(确定元素集合)和合并(组合集合)。示例展示了如何用并查集配合Kruskal算法构建最小生成树。掌握并查集能高效处理复杂问题,优化后的查找和合并操作接近O(1)复杂度,是解决算法挑战的利器。
33 4
|
2月前
|
算法 计算机视觉 开发者
燃爆全场!Python并查集:数据结构界的网红,让你的代码炫酷无比!
【7月更文挑战第16天】并查集,Python中的效率明星,处理不相交集合合并与查询。用于社交网络分析、图像处理、图论算法等领域。优雅实现结合路径压缩和按秩合并
28 1
|
2月前
|
算法 程序员 计算机视觉
Python并查集:数据结构界的肌肉男,让你在编程路上无所畏惧!
【7月更文挑战第16天】并查集,一种处理不相交集合合并与查询的数据结构,被誉为编程的“肌肉男”。它提供Find(找根节点)和Union(合并集合)操作,常用于好友关系判断、图像处理、集合合并等。Python实现中,路径压缩和按秩合并优化效率。并查集的高效性能使其成为解决问题的强大工具,助力程序员应对复杂挑战。
40 0
|
2月前
|
存储 算法 C++
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
46 0