本文记录下树结构下的并查集和其在Kruskal计算最小生成树算法中的应用

一、何为并查集

  并查集,顾名思义对数据进行合并和查询,因为是树结构的应用,合并即将两个数据安置在树中,查询即查询某个数据的祖宗结点。其意义在于将许多看似不相关的数据通过一些线索分组,下面举个例子。

  心理学中有个著名的六度分离理论,“你和任何一个陌生人之间所间隔的人不会超过五个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”

  现有11个人,这11个人编号1~14的数据,有如下10条线索:1、2彼此认识;3、4彼此认识;5、2彼此认识;4、6彼此认识;2、6彼此认识;7、11彼此认识;8、7彼此认识;9、7彼此认识;9、11彼此认识;1、6彼此认识。那么我们想要认识这11个人,只需要认识他们之中的几个,通过这几个人便可以要到所有人的联系方式,利用并查集将这11个人根据线索分组。

二、如何合并、查询

我认为有两个原则,一个概念,以左为尊原则和一撸到底原则,同时在一撸到底的过程中会伴随路径压缩的概念。以左为尊指让右方所在的组归为左方所在的组,一撸到底指分组时要让自己组长以左为尊,具体是什么通过分析上面的例子看一下。
起初每人自成一组共11组并自认组长(1 2 3 4 5 6 7 8 9 10 11)

  1. 第一条线索1、2,以左为尊即2组此时归为1组,2号的组长为1号(1 1 3 4 5 6 7 8 9 10 11)
  2. 第二条线索3、4,同上以左为尊4组归为3组,4号的组长为3号(1 1 3 3 5 6 7 8 9 10 11)
  3. 第三条线索5、2,注意以左为尊不是编号越小越尊贵而是输入的顺序,这里需要让2号所在的组归为5号所在的组,2号在1组,其组长为1号,贯彻一撸到底,让1号带着2号归为5号所在的5组(5 1 3 3 5 6 7 8 9 10 11)
  4. 第四条线索4、6,6组归为4号所在的3组(5 1 3 3 5 3 7 8 9 10 11)
  5. 第五条线索2、6,此时6号的组长为3号;2号的组长为1号、1号的组长又为5号,即一撸到底后2号组长为5号,在这个过程中发生了路径压缩,2号到组长5号的距离中间横着的1号被赶跑,也就是现在2号想要找到组长不需要在通过1号了。再将6号的所在的组以左为尊(5 5 5 3 5 3 7 8 9 10 11)
  6. 第六条线索7、11,以左为尊(5 5 5 3 5 3 7 8 9 10 7)
  7. 第七条线索8、7,以作为尊(5 5 5 3 5 3 8 8 9 10 7)
  8. 第八条线索9、7,一撸到底后以左为尊(5 5 5 3 5 3 8 9 9 10 7)
  9. 第九条线索9、11,一撸到底过程中路径压缩,11号先找到7号,而7号也不能一步到达自己的组长9号,7号到组长9号间的8号被赶跑(5 5 5 3 5 3 9 9 9 10 9)
  10. 第十条线索1、6,一撸到底过程中路径压缩,6号到组长5号中间的3号被赶跑(5 5 5 3 5 5 9 9 9 10 9)
线索/人 1 2 3 4 5 6 7 8 9 10 11
起初 1 2 3 4 5 6 7 8 9 10 11
1、2 1 1 3 4 5 6 7 8 9 10 11
3、4 1 1 3 3 5 6 7 8 9 10 11
5、2 5 1 3 3 5 6 7 8 9 10 11
4、6 5 1 3 3 5 3 7 8 9 10 11
2、6 5 5 5 3 5 3 7 8 9 10 11
7、11 5 5 5 3 5 3 7 8 9 10 7
8、7 5 5 5 3 5 3 8 8 9 10 7
9、7 5 5 5 3 5 3 8 9 9 10 7
9、11 5 5 5 3 5 3 9 9 9 10 9
1、6 5 5 5 3 5 3 9 9 9 10 9

总结下来,合并就是将两个结点安插在树中,安插前就需要查询左边点和右边点的祖宗结点(一撸到底),在查询过程中可能有的点会发现自己以为的祖宗结点其实是父结点,这样的点会找到自己真正的祖宗结点(路径压缩),最后让左边的点跟随右边的点(以左为尊)。以上例子中的组长便是祖宗结点,起初每个点的祖宗结点就是自己,并查集实现了结点们认祖归宗的过程,最后有几个祖宗结点,数据就分为了几组。该例为3个祖宗,分别是5、9、10,即通过这三个人就可以认识所有的11个人。

#include <iostream>
#include <algorithm>
#include <stdio.h>using namespace std;int point_data[101];//索引为自己的结点号,值为父结点号(可能是祖宗节点)
int n, m;//结点数,线索数int query(int v) {//寻找祖宗结点,查询if (point_data[v] == v)return v;else {point_data[v] = query(point_data[v]);//一撸到底原则,伴随路径压缩return point_data[v];}
}void merge(int left, int right) {//两个结点合并int t1 = query(left);//获得left祖宗结点int t2 = query(right);//获得right祖宗结点if (t1 != t2)point_data[t2] = t1;//以左为尊原则return;
}int main() {cout << "输入结点数和相关信息数:";cin >> n >> m;//有多少结点,多少个相关性信息for (int i = 1; i <= n; i++)point_data[i] = i;cout << "输入相关的结点" << endl;for (int i = 1; i <= m; i++) {int x, y;//x和y相关cin >> x >> y;merge(x, y);//合并x和y}cout << "祖宗结点有:";for (int i = 1; i <= n; i++)if (point_data[i] == i)//该点一定为一个祖宗结点cout << i << " ";cout << endl;return 0;
}

三、并查集在Kruskal最小生成树算法中的应用

  并查集可以查询某两个结点的祖宗结点,如果两个结点的祖宗结点一样,且这两个结点间有一条边,则从树结构变成了有闭合回路的图。相信已经很明显了,并查集可以判断在图中加入一条边后是否形成环,而这正是Kruskal最小生成树算法的关键。

  大致说下该宗室级算法,首先将图中每条边去除并按权值自然顺序排序,然后依次将边补充回图中,如果形成了回路则该边舍弃,循环该步骤直到所有点被边连接。

#include <iostream>
#include <stdio.h>
#include <algorithm>using namespace std;struct Line {//每条边int p1;//点int p2;//点int weight;//权值
};int point_data[101];//并查集数组int query(int i) {//查询,寻找祖宗结点if (point_data[i] == i)return point_data[i];else {point_data[i] = query(point_data[i]);//路径压缩return point_data[i];}
}bool merge(int left, int right) {//合并int t1 = query(left);//获得祖先结点int t2 = query(right);//获得祖先结点if (t1 != t2) {//如果没有共同的祖先结点,则无回路point_data[t2] = t1;return true;}return false;
}int main() {int n, m;cout << "输入点、边数:";cin >> n >> m;Line lines[101];cout << "输入边的信息" << endl;for (int i = 1; i <= m; i++)cin >> lines[i].p1 >> lines[i].p2 >> lines[i].weight;auto cmp = [](const Line& a, const Line& b)->int {return a.weight < b.weight; };sort(lines + 1, lines + 1 + m, cmp);//按照权值排序for (int i = 1; i <= n; i++)//并查集初始化point_data[i] = i;int count = 0, sum = 0;//已用边数,当前总权值cout << "所用边权值依次为:";for (int i = 1; i <= m; i++) {if (merge(lines[i].p1, lines[i].p2)) {//如果不会形成回路cout << lines[i].weight << " ";count++;//已用边数sum += lines[i].weight;}if (count == n - 1)//n-1条边恰好可将n个点相连break;}cout << endl << "总权值为:" << sum << endl;return 0;
}

一口气——并查集及其在Kruskal算法的应用相关推荐

  1. 【并查集】【Kruskal】剑鱼行动

    L i n k Link Link SSL 1618 D e s c r i p t i o n Description Description 给出N个点的坐标,对它们建立一个最小生成树,代价就是连 ...

  2. Kruskal算法和并查集

    Kruskal算法 步骤: 第一步:给所有边按照从小到大顺序排列(直接使用库函数qsort / sort). 第二步:从小到大依次考察每条边(u,v),在执行第二步时会出现以下两种情况: 情况1:u和 ...

  3. Kruskal算法与并查集

    Kruskal算法与并查集 一.Kruskal算法 1. 概念 Kruskal算法就是按照图中各个边上的权值大小进行递增排序,以此来构造最小生成树. 2.重点解析 在由Kruskal实现最小生成树的过 ...

  4. LA 3644 易爆物 并查集

    题目链接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show ...

  5. CCF201703-4 地铁修建(100分)【Kruskal算法+二分+最短路】

    试题编号: 201703-4 试题名称: 地铁修建 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号 ...

  6. CCF201812-4 数据中心(100分)【Kruskal算法】

    试题编号: 201812-4 试题名称: 数据中心 时间限制: 1.0s 内存限制: 512.0MB 样例输入 4 5 1 1 2 3 1 3 4 1 4 5 2 3 8 3 4 2 样例输出 4 样 ...

  7. HDOJ 1863畅通工程(最小生成树kruskal算法并查集实现)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1863 最小生成树kruskal算法:http://www.zhuoda.org/irini/78592.h ...

  8. 并查集及其简单应用:优化kruskal算法

    并查集是一种可以在较短的时间内进行集合的查找与合并的树形数据结构 每次合并只需将两棵树的根合并即可 通过路径压缩减小每颗树的深度可以使查找祖先的速度加快不少 代码如下: int getfather(i ...

  9. 并查集与贪心算法的应用之求解无向图的最小生成树

    一,介绍 本文介绍使用Kruskal算法求解无向图的最小生成树.Kruskal是一个贪心算法,并且使用了并查集这种数据结构. 关于并查集的介绍,参考:数据结构--并查集的原理及实现 二,构造一个无向图 ...

最新文章

  1. 【视频】SQL Server 2008 R2 StreamInsight - 多源复杂事件处理
  2. jQuery 实战读书笔记之第四章:使用特性、属性和数据
  3. linux 禁ping设置
  4. 洛谷 - P2472 [SCOI2007]蜥蜴(最大流)
  5. PHP十六个魔术方法
  6. GitHub:Python 强化学习实用指南
  7. VSCode每打开一次文件弹出一个git弹窗:-login -i rev-parse --show-toplevel
  8. C语言格式化读写文件
  9. Git------GitHub官网
  10. 中国历史上成功的两人合作, 改进, 提高的例子
  11. qmc3格式文件转为mp3
  12. css宋体代码_css怎么设置字体为宋体
  13. 得物 × StarRocks:潮流网购社区的极速 OLAP 实践
  14. 鸿蒙os官方版下载,鸿蒙os2.0正式版
  15. 绿幕背景视频抠图替换
  16. 软件设计师-知识的整理
  17. 沉痛哀悼我的弟弟-恽小华-南理工教授,候选中科院院士——一声叹息
  18. 我错过了乔布斯和初代 iPhone,十年后幸好没错过你
  19. 怎么提高程序的可修改性
  20. 进阶篇:3.9)3d打印件设计

热门文章

  1. 在LC- 3中,机器码实现右移一位
  2. buu部分ctf crypto题解
  3. Libnids--函数调用顺序之nids_init()
  4. Sonarqube 通过docker-compose启动报错,提示virtual memory areas vm.max_map_count [65530] is too low
  5. C/C++语言实现 学生管理系统
  6. Mondrian + JPivot环境配置和演示
  7. amd显卡没有屏幕旋转快捷键,自己写一个
  8. 聊一聊,面试为什么大厂钟爱问源码,真的是(问)造火箭=>(做)拧螺丝?如何读源码?
  9. 2.MySQL ---- 修改数据库的字符集(日常小技巧)
  10. Netty In Action中文版