数据结构-并查集

news2024/11/28 14:33:06

并查集原理   

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

  一般可以用数组来表示并查集,数据的下标就是每个数据的编号,对应的值如果是负数,那么就代表它自成一个集合,也就是一个根结点。如图,初始值一般都是负数,也就是每个元素都自成一个集合,如果一个元素是根,那么负数的绝对值则代表这个树有多少结点;如果不是负数,那么则说明这个元素不是根,且对应的值存的是父亲结点的下标。

  实际应用中也可以通过加入哈希表来设置更多的映射关系,这样的话可以将数组的下标作为key值,然后可以存人名这些。

  所以并查集其实也是多棵树组成的森林。

用并查集表示就是

 元素之间可以合并,并且可以制定合并规则。集合与集合之间也可以合并。

 综上,我们可以知道并查集可以解决以下问题:

1.查找某个元素属于哪个集合。沿着数组表示的树形关系向上可以一直找到根。

2.查看两个元素是否属于同一个集合。可以看找到的根是否相同,以此来判断是否属于同一个集合。

3.可以将两个集合归并成一个集合。

4.求集合的个数。其实也就是根的个数,可以遍历数组,记录下标为负数的元素即是集合的个数。

并查集简单实现

#pragma once

#include <vector>

//可以设计成模板,加入哈希表来存放更多的映射关系

class UnionFindSet
{
public:
	UnionFindSet(int size)
		:_set(size, -1)
	{}
	~UnionFindSet()
	{}
	size_t FindRoot(int x)
	{
		int root = x;
		while (_set[root] >= 0)
			root = _set[root];  // 向上找到根

		while (_set[x] >= 0)    // 向上遍历,依次修改父亲的父亲结点,使其变为根结点的儿子。// 路径压缩
		{
			int parent = _set[x];
			_set[x] = root;
			x = parent;
		}
		return root;
	}

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

		if (abs(_set[root1]) < abs(_set[root2]))   // 小优化,每次合并都合并到结点更多的树中,可以减少层数
			std::swap(_set[root1], _set[root2]);

		if (root1 != root2)  // 如果相等说明在一个集合内,没必要合并
		{
			_set[root1] += _set[root2];
			_set[root2] = root1;    // 这里默认合并到root1
		}
	}

	int SetCount()  // 找根结点个数
	{
		size_t count = 0;
		for (size_t i = 0; i < _set.size(); ++i)
		{
			if (_set[i] < 0)
				count++;
		}
		return count;
	}
private:
	std::vector<int> _set;
};

void TestUFS()
{
	UnionFindSet u(10);

	u.Union(0, 6);
	u.Union(7, 6);
	u.Union(7, 8);

	u.Union(1, 4);
	u.Union(4, 9);

	u.Union(2, 3);
	u.Union(2, 5);

	std::cout << u.SetCount() << std::endl;
}

 另外说下压缩路径的问题,当并查集的数据非常大时,我们要找到这个元素的根,可能就需要向上找很久,有一种解决方案就是,在每次查找的时候,如果它的父亲结点不是根结点的话,就将它放到根结点的儿子结点。这样就能减少遍历的次数。

并查集虽然是一种数据结构,但是有时候又可以是一种解决问题的思路。

比如这道题,可以直接手搓一个简单的并查集,很容易就秒掉。

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size();
        vector<int> set(n,-1);
        auto findRoot = [&set](int x)
        {
            while(set[x] >= 0)
                x = set[x];
            return x;
        };

        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(isConnected[i][j] == 1)
                {
                    int root1 = findRoot(i);
                    int root2 = findRoot(j);
                    if(root1 != root2)
                    {
                        set[root1] += set[root2];
                        set[root2] = root1;
                    }
                }
            }
        }

        int count = 0;
        for(auto &x : set)
        {
            if(x < 0)
                count++;
        }

        return count;
    }
};

 总结并查集的特点:

1.一个位置的值是负数,那么它就是树的根,这个负数的绝对值就是这个树结点的个数。

2.一个位置的值是正数,那么这个正数就是它父亲结点的下标。

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

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

相关文章

cool Nodejs后端框架 如何快速入门 写一个接口

1.cool 框架 js前端开发者 想自己写后端接口 快速入门的就是node.js 了 可以用这个框架自己做一些东西 或者实现前后端的开发 2.目录结构 这个基本上 就是cool 框架的项目结构 主要是 这个src 中的modules 文件夹 这个文件夹 主要是一些接口模块 比如 business 中 相当于…

leetcode 448. 找到所有数组中消失的数字

用的最土的办法&#xff0c;将数组nums中出现过的数字用map记录下来&#xff0c;再遍历1~n中的所有数字&#xff0c;凡是未在map中出现过的即为我们要找的数字。 Java代码如下&#xff1a; class Solution {public List<Integer> findDisappearedNumbers(int[] nums) {i…

品牌之门:概率与潜力的无限延伸

在品牌的世界里&#xff0c;每一个成功的推广都像是打开一扇门&#xff0c;从未知走向已知&#xff0c;从潜在走向显现。这扇门&#xff0c;既是品牌的起点&#xff0c;也是品牌发展的无限可能。 品牌&#xff0c;就像一扇紧闭的门&#xff0c;它静静地矗立在那里&#xff0c;…

优先级队列(堆)_PriorityQueue

前言 想要看如何使用可以通过目录跳转到 PriorityQueue的使用 优先级队列 概念 队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c;一般出队 列时&#xff0c;可能需要优先级高的元素先出队列&#xff0c;该中场…

linuxqq关闭主面板后无法再次打开的问题

文章目录 前言解决方案强调一点 前言 听说QQ出了linux版&#xff0c;所以来试试。结果试试就逝世。这次记录一个关闭后没办法打开的解决办法。 解决方案 刚安装好后如果点了关闭&#xff0c;系统托盘里也没有&#xff0c;点击图标又是重新登录。当然&#xff0c;我们最简单、…

反序列化漏洞(一)Shiro漏洞CVE-2016-4437复现

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、前言 春节后第一篇&#xff0c;祝大家龙年一切顺利&…

书生浦语大模型实战营-课程笔记(1)

模型应用过程&#xff0c;大致还是了解的。和之前实习做CV项目的时候比起来&#xff0c;多了智能体这个环节。智能体是个啥&#xff1f; 类似上张图&#xff0c;智能体不太清楚。感觉是偏应用而不是模型的东西&#xff1f; 数据集类型很多&#xff0c;有文本/图片/视频。所以…

仰暮计划|“​他们艰苦半生,但真的希望祖国安祥,山河无恙”

自述&#xff0c;自赎 我没有在那个年代生活过&#xff0c;我一出生就是盛世中国&#xff0c;看遍了祖国的大好河山。但我没想到&#xff0c;走了这么远的路&#xff0c;吃了这么多的苦的爷爷会一直跟我说“不是国家不好&#xff0c;只是中国的钱拿去还债了&#xff0c;过了那…

什么是 Docker 容器?以及操作 Docker 容器相关的命令汇总

镜像仓库常用指令&#xff1a;Docker 镜像仓库是什么&#xff1f;有哪些镜像仓库命令&#xff1f; 镜像常用指令&#xff1a;操作 Docker 镜像的常用命令 1. 什么是容器&#xff1f; 容器是镜像的运行实体。容器是基于镜像创建的可运行实例&#xff0c;并且单独存在&#xff0…

FastAI 之书(面向程序员的 FastAI)(八)

原文&#xff1a;www.bookstack.cn/read/th-fastai-book 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第二十章&#xff1a;总结思考 原文&#xff1a;www.bookstack.cn/read/th-fastai-book/cedc7ab42349d210.md 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA…

Github 2024-02-14 开源项目日报 Top9

根据Github Trendings的统计&#xff0c;今日(2024-02-14统计)共有9个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Rust项目4TypeScript项目1PowerShell项目1Java项目1JavaScript项目1Jupyter Notebook项目1非开发语言项目1Pyth…

每日五道java面试题之java基础篇(八)

第一题.CopyOnWriteArrayList的底层原理是怎样的 ⾸先CopyOnWriteArrayList内部也是⽤过数组来实现的&#xff0c;在向CopyOnWriteArrayList添加元素时&#xff0c;会复制⼀个新的数组&#xff0c;写操作在新数组上进⾏&#xff0c;读操作在原数组上进⾏并且&#xff0c;写操作…

Hive调优——合并小文件

目录 一、小文件产生的原因 二、小文件的危害 三、小文件的解决方案 3.1 小文件的预防 3.1.1 减少Map数量 3.1.2 减少Reduce的数量 3.2 已存在的小文件合并 3.2.1 方式一&#xff1a;insert overwrite (推荐) 3.2.2 方式二&#xff1a;concatenate 3.2.3 方式三&#xff…

DOM事件练习1

DOM事件练习1 1. 演示效果 2. 代码分析 用 ul 创建四个 li 列表整个列表的背景是红色的&#xff0c;鼠标悬浮在列表上&#xff0c;一行的变为蓝色点击任意列表&#xff0c;整个列表的背景变为白色&#xff0c;被点击的列表变为粉色需要用到 js 的点击事onclick件和forEach循环…

手撕Promise

文章目录 一、Promise的初体验1.初体验——抽奖案例 二、Promise的实践练习1.实践练习——fs读取文件2.实践练习——AJAX请求 三、Promise的常见骚操作1.封装fs读取文件操作2.util.promisify方法进行promise风格转化3.封装原生的Ajax4.Promise实例对象的两个属性&#xff08;1&…

《Think in Java》

《Think in Java》 第一章&#xff1a;对象导论 1.1 抽象过程 1&#xff09;万物皆对象。 2&#xff09;程序是对象的集合&#xff0c;它们通过发送消息来告诉彼此所要做的。 3&#xff09;每个对象都有其他对象构成的存储&#xff0c;一个对象可以复用其他对象&#xff0c;从而…

Sentinel 流控-关联模式

关联模式 A关联B, 当B流控后,A 的流控规则也生效了 条件 A 设置高级流控规则,关联 B资源B 设置普通流控规则(独立规则)实例 接口编写 package com.learning.springcloud.order.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.s…

论文解读:MobileOne: An Improved One millisecond Mobile Backbone

论文创新点汇总&#xff1a;人工智能论文通用创新点(持续更新中...)-CSDN博客 论文总结 关于如何提升模型速度&#xff0c;当今学术界的研究往往聚焦于如何将FLOPs或者参数量的降低&#xff0c;而作者认为应该是减少分支数和选择高效的网络结构。 概述 MobileOne(≈MobileN…

DS:树及二叉树的相关概念

创作不易&#xff0c;兄弟们来波三连吧&#xff01;&#xff01; 一、树的概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c…

顾问聘请协议(模板)

甲方&#xff1a;________________   乙方&#xff1a;________________ 诚信合作是一切事业发展的基础&#xff0c;外部智力是企业进步的源泉。甲、乙双方经友好协商达成本协议&#xff0c;甲方愿意聘请乙方为特邀管理顾问&#xff0c;乙方愿按本协议内容与甲方合作。 一、合…