算法模板:模拟数据结构之并查集

简介: 算法模板:模拟数据结构之并查集


并查集


并查集作用:

1.将两个集合合并

2.询问两个元素是否在一个集合当中


基本原理:


每个集合用一颗树来表示。树根的编号就是整个集合的编号。每个节点都存的是它的父节点,即 p [x] 表示 x 的父节点。


p[x]中储存的是每个节点的父节点,一开始并不是树状的,


而是一个个单独的节点,每个节点都是根节点,都有集合编号,然后通过不断的合并才形成的树状结构


问题一: 如何判断树根


if (p[x]==x)


除根节点以为所有节点都存的是自身的父节点,只有根节点存的是它自己。


问题二: 如何求x的集合编号


没找到就一直访问到它的父节点,直到找到位置。


while (p[x] != x) x = p[x]


优化:路径压缩

只要某一个元素找的根节点

就把这个元素的所有祖宗节点都改成根节点。


int find(int x)
{
  if(p[x]!=x)// x不是自身的父亲,即x不是该集合的代表
    return p[x]=find(p[x]);
    return p[x]; // 查找x的祖先直到找到代表,于是顺手路径压缩
}


问题三:如何合并两个集合


     p [find(a)] = p[find(b)];


p[x]=x的集合编号,p[y]是y的集合编号


代码实现


#include<bits/stdc++.h>
using namespace std;q
const int N = 1e6+10;
int p[N];
int find(int x)
{
  if(p[x]!=x)// x不是自身的父亲,即x不是该集合的代表
    return p[x]=find(p[x]);
    return p[x]; // 查找x的祖先直到找到代表,于是顺手路径压缩
}
int main()
{
  int n,m;
  cin>>n>>m;  
  for(int i = 1 ; i <= n ; i ++)  p[i]=i;
    //开始时每个节点都是父节点
  while(m--)
  {
    string x; cin>>x;
    int a,b; cin>>a>>b;
    if(x=="M")
    p[find(a)]=find(b);//a集合的根节点的父节点变成 b集合的根节点 完成a集合与b集合的合并
    else
    {
      if(find(a)==find(b))
      cout<<"Yes";
      else
      cout<<"No";
      puts("");
    }
  }
  return 0;
}


村村通

某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 “村村通工程” 的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?


输入格式


输入包含若干组测试测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目 nnn 和道路数目 mmm ;随后的 mmm 行对应 mmm 条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从 111 到 nnn 编号。


注意:两个城市间可以有多条道路相通。


输出格式


对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。


输入 #1


4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0


输出 #1


1
0
2
998


思路:


先初始化,将自己父亲等于自己


**输入两个村庄后就把它们连起来,输入完毕后遍历 从 1 到 n,判断 节点是不是等于他们的父节点 **


所以如果i的父亲为它本身的话 说明 编号为 i 的这条路,与其他路不连通,ans++


但还有一种情况是会有一个节点是所有其他节点的祖先节点,也而且祖先节点也等于他本身、


所以最后需要 ans - 1


#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int p[N];
int find(int x)
{
  return (p[x]!=x)?p[x]=find(p[x]):p[x];
}
int main()
{
  int n,m;
  while(cin>>n>>m)
  {
    int a,b;
    int ans=0;
    for(int i = 1 ; i <= n ; i ++)
    p[i]=i;
    while(m--)
    {
      cin>>a>>b; 
      a=find(a),b=find(b);
      p[a]=p[b];
    }
    for(int i = 1 ; i <= n; i ++)
    {
      if(find(i)==i)
      ans++;
      //如果自己等于自己的父亲 就说明 编号为 i 的这条路,与其他路不连通 
    }
    cout<<ans-1<<"\n";
        //要减一是因为如果不用修一条路的话 那就会有一个节点是所有其他节点的祖先节点 所以要减去1 
  }
  return 0; 
 } 


完结散花

ok以上就是对 模拟数据结构之并查集 的全部讲解啦,很感谢你能看到这儿。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。

相关文章
|
1月前
|
算法 开发者 计算机视觉
燃爆全场!Python并查集:数据结构界的网红,让你的代码炫酷无比!
在编程的世界里,总有一些数据结构以其独特的魅力和高效的性能脱颖而出,成为众多开发者追捧的“网红”。今天,我们要介绍的这位明星,就是Python中的并查集(Union-Find)——它不仅在解决特定问题上大放异彩,更以其优雅的设计和强大的功能,让你的代码炫酷无比,燃爆全场!
29 0
|
3月前
|
算法
【算法】前缀和——二维前缀和模板题
【算法】前缀和——二维前缀和模板题
|
6天前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
10 3
|
18天前
|
存储 缓存 算法
如何通过优化算法和代码结构来提升易语言程序的执行效率?
如何通过优化算法和代码结构来提升易语言程序的执行效率?
|
2月前
|
算法 JavaScript 前端开发
第一个算法项目 | JS实现并查集迷宫算法Demo学习
本文是关于使用JavaScript实现并查集迷宫算法的中国象棋demo的学习记录,包括项目运行方法、知识点梳理、代码赏析以及相关CSS样式表文件的介绍。
第一个算法项目 | JS实现并查集迷宫算法Demo学习
|
1月前
|
存储 算法 Python
火箭般的提升!学会Python并查集,让你的算法能力飞跃新高度!
火箭般的提升!学会Python并查集,让你的算法能力飞跃新高度!
32 1
|
2月前
|
Python
逆天改命!掌握Python并查集,数据结构难题从此不再是你的痛!
在编程旅程中,遇到棘手的数据结构难题是否让你苦恼?别担心,Python并查集(Union-Find)是你的得力助手。这是一种高效处理不相交集合合并及查询的数据结构,广泛应用于网络连通性、社交网络圈子划分等场景。通过维护每个集合的根节点,它实现了快速合并与查询。本文将介绍并查集的基本概念、应用场景以及如何在Python中轻松实现并查集,帮助你轻松应对各种数据结构挑战。
33 3
|
2月前
|
算法 计算机视觉 Python
Python并查集大揭秘:让你在算法界呼风唤雨,秒杀一切复杂场景!
在编程与算法的广袤天地中,总有一些工具如同神兵利器,能够助你一臂之力,在复杂的问题前游刃有余。今天,我们就来深入探讨这样一件神器——Python并查集(Union-Find),看看它是如何让你在算法界呼风唤雨,轻松应对各种复杂场景的。
58 2
|
2月前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
2月前
|
Python
告别低效!Python并查集:数据结构界的超级英雄,拯救你的编程人生!
告别低效!Python并查集:数据结构界的超级英雄,拯救你的编程人生!
26 0