理解使用并查集

news2024/9/25 19:14:40

目录

一.并查集原理

1.概念:

2.性质

3.形式

4. 合并方式

二.并查集实现

1.成员变量

2.构造函数

3.查找根

4.合并集合

5.判断是否在一个集合

6.查看集合数量

三.并查集总代码


前言:理解并查集是为了接下来学习图要用,而会使用并查集,则可以在做某些OJ题目时更加简单。

一.并查集原理

1.概念:

        在一些问题中,需要将n个不同的元素划分成一些不相交的集合开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于哪个集合的运算。适合于描述这类问题的抽象数据类型称为并查集

2.性质

① 数组的下标对应集合中元素的编号

② 数组中如果为负数,其中的负号代表它是根,数字代表该集合中元素个数

③ 数组中如果为非负数,代表该元素父亲在数组中的下标

3.形式

 

4. 合并方式

        如果两个集合中的元素发生合并,那么怎么办呢?

解决方法:

① 查找元素属于哪个集合

        沿着数组表示的树形关系往上一直找到根(根:树中元素为负数的位置) 

② 查看两个元素是否属于同一个集合

        沿着数组表示的树形关系往上一直找到树的根,如果根相同说明在同一个集合,否则不再同一个集合。

③ 将两个集合归并成一个集合

        先将两个集合中的元素合并,再将一个集合名称改为另一个集合的名称。

        合并的方式就是将其中一个根的数字加到另一个根的数字上,然后再将这个根中的数组变成新的根元素的位置。

        将0和1的集合合并,变成如图所示。

        上面的解决方法就是并查集可以解决的问题,除了上面3个,还有第4个:

④ 查看集合的个数

        遍历数组,数组中元素为负数的个数即为集合的个数。

二.并查集实现

1.成员变量

        该成员就为一个vector容器。 

private:
	std::vector<int> _ufs;

2.构造函数

        根据想要构造的vector的数量,来开辟足够的空间,并全部初始化为-1。

UnionFindSet(size_t n)
	: _ufs(n, -1)
{}

3.查找根

        遍历数组,找到的第一个为负数的元素就是其中一个集合的根。这里为了优化,我们可以进行路径压缩:遍历数组,找到大于0的元素,就先保存它的父节点,然后再将该元素直接给root(相当于连上了root,父亲变为root),即将该元素的数字变为root的位置,最后再继续往上,让他的父节点直接连到root。

size_t FindRoot(int x)
{
	int root = x;
	while (_ufs[root] >= 0)
	{
		root = _ufs[root];
	}

	// 路径压缩
	while (_ufs[x] >= 0)
	{
		int parent = _ufs[x];
		_ufs[x] = root;

		x = parent;
	}

	return root;
}

4.合并集合

        先保存两个集合的根,如果这两个根是相同的,就说明这两个元素本身就是一个集合的,就不需要去合并了。然后为了优化,我们让数据量小的往大的合并。因为我们默认root1的集合是数据量大的那个,如果实际上root2的数据量更大,那么就交换root1和root2。

void Union(int x1, int x2)
{
	int root1 = FindRoot(x1);
	int root2 = FindRoot(x2);

	// 如果本身就在一个集合就没必要合并了
	if (root1 == root2)
	{
		return;
	}

	// 控制数据量小的往大的集合合并
	if (abs(_ufs[root1]) < abs(_ufs[root2]))
	{
		swap(root1, root2);
	}

	_ufs[root1] += _ufs[root2];
	_ufs[root2] = root1;
}

5.判断是否在一个集合

        之间通过调用FindRoot函数,看根是否相同,相同就是在一个集合。

bool InSet(int x1, int x2)
{
	return FindRoot(x1) == FindRoot(x2);
}

6.查看集合数量

        遍历数组,有多少个负数就有多少个集合。

size_t SetSize()
{
	size_t size = 0;
	for (size_t i = 0; i < _ufs.size(); ++i)
	{
		if (_ufs[i] < 0)
		{
			++size;
		}
	}

	return size;
}

三.并查集总代码

#pragma once
#include <vector>

class UnionFindSet
{
public:
	UnionFindSet(size_t n)
		: _ufs(n, -1)
	{}

	size_t FindRoot(int x)
	{
		int root = x;
		while (_ufs[root] >= 0)
		{
			root = _ufs[root];
		}

		// 路径压缩
		while (_ufs[x] >= 0)
		{
			int parent = _ufs[x];
			_ufs[x] = root;

			x = parent;
		}

		return root;
	}

	void Union(int x1, int x2)
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);

		// 如果本身就在一个集合就没必要合并了
		if (root1 == root2)
		{
			return;
		}

		// 控制数据量小的往大的集合合并
		if (abs(_ufs[root1]) < abs(_ufs[root2]))
		{
			swap(root1, root2);
		}

		_ufs[root1] += _ufs[root2];
		_ufs[root2] = root1;
	}

	bool InSet(int x1, int x2)
	{
		return FindRoot(x1) == FindRoot(x2);
	}

	size_t SetSize()
	{
		size_t size = 0;
		for (size_t i = 0; i < _ufs.size(); ++i)
		{
			if (_ufs[i] < 0)
			{
				++size;
			}
		}

		return size;
	}
private:
	std::vector<int> _ufs;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux:系统性能监控工具-tsar安装和使用

在上家公司做性能压力测试时就用过tsar&#xff0c;但总结文档留在了内部&#xff0c;正好借着最近工作内容又用上了tsar&#xff0c;总结起来 目录前言tsar介绍总体架构安装tasrtsar配置介绍配置文件定时任务配置日志文件tsar使用tsar实际使用参考查看可用的监控模块列表查看C…

本松新材创业板IPO终止:业绩下滑,客户较集中,周永松为实控人

撰稿|汤汤 来源|贝多财经 近日&#xff0c;深圳证券交易所披露的信息显示&#xff0c;杭州本松新材料技术股份有限公司&#xff08;下称“本松新材”&#xff09;提交了撤回上市申请文件的申请&#xff0c;保荐人财通证券也撤回对该公司的保荐。因此&#xff0c;深交所终止了…

目标检测:YOLOV3技术详解

目标检测&#xff1a;YOLOV3技术详解前言主要改进DarkNet53新的分类器正负样本的匹配损失函数前言 YOLOV3是V2的升级版&#xff0c;也是原作者的绝笔&#xff0c;V3主要还是把当时一些有用的思想融入了进来&#xff0c;没有什么创新型的突破&#xff0c;具体细节我们下面介绍。…

【安卓逆向】Frida入门与常用备忘

【安卓逆向】Frida入门与常用备忘前置知识什么是hook&#xff1f;hook的作用常见的逆向工具Frida使用入门简介与资料参考备忘前置环境配置执行hook常用hook脚本/API前置知识 什么是hook&#xff1f; hook&#xff0c;译为“钩子”&#xff0c;是指将方法/函数勾住&#xff0c;…

2022-CSDN的一年

前言 马上要到兔年的春节&#xff0c;年前最后一个版本顺利上线&#xff0c;闲下来两天&#xff0c;可以对过往一年进行一下总结&#xff0c;说起来这是入职CSDN之后第一次自己将自己所思所想以以博客的形式发布在CSDN网站上&#xff0c;也是比较奇特的体验。语言表达能力不强&…

利用华为路由器配置单臂路由功能,实现多个vlan间通信

单臂路由&#xff0c;是通过一台路由器使不同VLAN之间互通的数据通过路由器进行三层转发。 如果在路由器上为每个 VLAN分配一个单独的路由器物理接口&#xff0c;那么随着VLAN数量的增口&#xff0c;必然需要更多的接口&#xff0c;而路由器能提供的接口数量有限&#xff0c;所…

Kubernetes 基本概念

Kubernetes 是什么 Kubernetes 是一个可移植、可扩展的开源平台。用于管理容器化的工作负载和服务&#xff0c;可促进声明式配 置和自动化。是谷歌保密了十几年的秘密武器Borg的开源版本&#xff0c;谷歌一直通过Borg系统管理着数量庞大 的应用程序集群。由于Kubernetes是基于…

元素排序 Comparable 和 Comparator 有什么区别?

1.字面含义不同 我们先从二者的字面含义来理解它&#xff0c;Comparable 翻译为中文是“比较”的意思&#xff0c;而 Comparator 是“比较器”的意思。Comparable 是以 -able 结尾的&#xff0c;表示它自身具备着某种能力&#xff0c;而 Comparator 是以 -or 结尾&#xff0c;…

7. R语言【相关性分析函数】:cov、cor、cor.test 和 【相关性检验函数】:cor.test、corr.test、pcor.test

b站课程视频链接&#xff1a; https://www.bilibili.com/video/BV19x411X7C6?p1 腾讯课堂(最新&#xff0c;但是要花钱&#xff0c;我花99&#x1f622;&#x1f622;元买了&#xff0c;感觉讲的没问题&#xff0c;就是知识点结构有点乱&#xff0c;有点废话&#xff09;&…

二、TortoiseGit的安装

1、TortoiseGit的安装 1.1、TortoiseGit简介 (1)TortoiseGit是一个基于TortoiseSVN的Git的Windows Shell接口。它是开源的&#xff0c;可以免费使用。 (2)TortoiseGit是git的比较好用的一个图形化工具。 1.2、软件下载 (1)下载地址 Download – TortoiseGit – Windows S…

84. 双向循环神经网络

1. 未来很重要 取决于过去和未来的上下文&#xff0c;可以填很不一样的词目前为止RNN只看过去在填空的时候&#xff0c;我们也可以看未来城 2. 双向RNN 两个隐状态层&#xff0c;并行计算隐状态&#xff0c;但是隐状态传播方向相反。 公式如下&#xff1a; 3. 推理 双向RNN不…

day16集合

1.Collection集合 1.1数组和集合的区别【理解】 相同点 都是容器,可以存储多个数据 不同点 数组的长度是不可变的,集合的长度是可变的 数组可以存基本数据类型和引用数据类型 集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类 1.2集合类体系结构【理解】…

web期末作业网页设计——APEX(网页源码)

大学生网页制作期末作业-HTMLCSSJavaScript&#xff08;包含源码&#xff09;-apex欢迎来到Apex英雄Apex-legends 充满各种机会的世界 边境远方 偏僻星球群 欢迎来到诸王峡谷 于2019年2月5日发行。玩家在游戏中将扮演外星战场上的星空战士。 《Apex英雄》是由《泰坦天降》制作组…

<栈>的概念结构实现【C语言版】

1.栈的概念及结构 栈存储数据的方式跟数组一样&#xff0c;都是将元素排成一行。只不过它还有以下 3 条约束。 ● 只能在末尾插入数据。 ● 只能读取末尾的数据。 ● 只能移除末尾的数据。 你可以将栈看成一叠碟子&#xff1a;你只能看到最顶端那只碟子的碟面&#xff0c…

微博图床挂了!

一直担心的事情还是发生了。作为hexo多年的使用者&#xff0c;微博图床一直是我的默认选项&#xff0c;hexotyporaiPic更是我这几年写文章的黄金组合。而图床中&#xff0c;新浪图床一直都是我的默认选项&#xff0c;速度快、稳定同时支持大图片批量上传更是让其成为了众多图床…

工具及方法 - 设计你的文件夹结构

电脑上资料总是很多&#xff0c;要如何管理&#xff0c;是每个人都需要处理的问题。 如果处理不好&#xff0c;时间一长&#xff0c;很多资料就可能不知所踪或者难以查找。 出现这种情况&#xff0c;让人头疼&#xff0c;还浪费了时间&#xff0c;降低了工作效率。 所以&…

springboot服务启动JMX监控

前言 java应用部署下在生产环境&#xff0c;肯定是少不了监控的&#xff0c;比如说我们想要监控JVM的线程使用情况&#xff0c;内存使用情况等等。这时候我们可以采用JMX来实现JVM监控&#xff0c;如果对JMX不熟悉&#xff0c;可以参见之前的 精通JVM监控&#xff0c;不知道J…

Java技能树-操作符(二)-练习篇

按位操作符 下面代码执行后的结果是&#xff1a; System.out.println(1 & 2); System.out.println(1 | 2);答案是&#xff1a;A 正确结果是&#xff1a; 0 3Process finished with exit code 0十进制&#xff1a;1 二进制&#xff1a;0000 0001 十进制&#xff1a;2 二进…

【SpringCloud】Erauke的基本原理与使用

【SpringCloud】Erauke的基本原理与使用 一、Eureka-提供者与消费者 【问】如果服务A调用了服务B&#xff0c;而服务B又调用了服务C&#xff0c;服务B的角色是什么&#xff1f; 二、Eureka的结构和作用 什么是Eureka&#xff1f; Eureka 解决服务调用的问题 order-servic…

计算机论文的参考文献,应该怎么引用? - 易智编译EaseEditing

参考文献的引用格式&#xff0c;要看期刊的要求&#xff0c;期刊会规定文章格式&#xff0c;这里面就包括参考文献的格式。 如果不是投稿到期刊&#xff0c;也会有相应的要求&#xff0c;按要求来就行。 不仅很参考文献的格式&#xff0c;还有很多细节也要注意&#xff1a; …