并查集,不就一并和一查?

article/2025/8/26 23:45:43

什么是并查集

并查集这种数据结构,可能出现的频率不是那么高,但是还会经常性的见到,其理解学习起来非常容易,通过本文,一定能够轻轻松松搞定并查集!

对于一种数据结构,肯定是有自己的应用场景和特性,那么并查集是处理什么问题的呢?

并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题,常常在使用中以森林来表示。在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

你可能还有点迷糊并查集能怎么玩,看完这篇然后回头看这两个问题(分别杭电1232和杭电1272)。

问题1:

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

这个问题很容易,给定的关系看看需要合并多少次就知道最少的建设道路数量。

问题二:

小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。


这个问题也很容易了,根据关系集合进行合如果两个元素已经属于一个集合,那就说明不满足要求啦。

并查集解析

通过上面介绍,相信你已经清楚并查集就是解决集合中一些元素的合并和查询问题,现在就带你解析这个算法。

初始化

开始时候森林中每个元素没有任何操作,它们之间是相互独立的。我们通常会使用数组来表示这个森林(数组下标对应第几个元素),在初始化的时候数组中的各个值为-1,表示各自自己是一个集合(各自为王),你可能会问为啥是-1而不是一个其他的数,那是因为用负数可以代表这个元素是某个集合的根,然后它的权值表示集合中元素的个数。

并 union(int a,int b)

这里合并,并没有你想象的直接合并那么简单,这里合并是合并a所在的集合和b所在的集合,但在操作层面a,b可能并不是根节点,所以也要先判断一下。

为了便于理解,这里罗列一下最初操作可能的情况,初始时候各个元素都是独立的集合,那么直接a指向b(或者b指向a)即arr[a]=b,同时为了表示这个集合有多少个,原本-1的b再次-1.即arr[b]=-2.表示以b为父根的集合节点有|-2|个。例如进行union(1,4),union(5,7)操作之后如图所示:

正常情况的union(int a,int b),假设我们就是a合并到b上,把b当成父集合来看。a、b都可能是叶子节点,也可能是根节点。

此时你可以先分别找到a,b的父节点fa,fb(这个根可能是它自己),然后合并fa和fb两个节点,例如上面如果union(1,5)那么其实就是等价union(4,7)。

为什么不直接操作a,b而是要找到他们的父亲进行操作?

原因1是因为a,b可能是叶子节点,其值是正的表示已经有父亲了,如果直接操作会使其与原来的集合分离开。另外集合中的数量(负数)也不能有效叠加。

原因2是因为合并的时候如果合并如果a,b是非根节点操作,可能会造成这个树的深度太大,不利于集合a中的查询效率。

查 search(int a)

查询,其实就是查询这个节点的根节点是啥(也称代表元),这个过程也有点类似递归的过程,叶子节点值如果为正,那么就继续查找这个值得位置的结果,一直到值为负数的时候说明找到根节点,可以直接返回。

不过在查询的过程中可以顺便路径优化,这样在频繁查询能够大大降低时间复杂度。

优化

你以为上面的就是并查集的全部?不不不,并查集还有不少需要掌握嘞,估计细心的人可能也会发现一些问题。

你可能会有疑问:

如何查看a,b是否在同一个集合?

查看是否在一个集合,只需要查看节点根祖先的结果是否相同即可。因为只有根的数值是负的,而其他都是正数表示指向的元素。所以只需要一直寻找直到不为正数进行比较即可!

a,b合并,究竟是a的祖先合并在b的祖先上,还是b的祖先合并在a上?

这里会遇到两种情况,这个选择也是非常重要的。你要弄明白一点:树的高度+1的化那么整个元素查询的效率都会降低!

所以我们通常是:小树指向大树(或者低树指向高树),这个使得查询效率能够增加!


当然,在高度和数量的选择上,还需要你自己选择和考虑。

查找途中能不能路径压缩

每次查询,自下向上。当我们调用递归的时候,可以顺便压缩路径(将当前数组的值等于递归返回的根节点的值),我们查找一个元素只需要直接找到它的祖先,所以当它距离祖先近那么下次查询就很快。并且压缩路径的代价并不大!

试想一下,如果一个分支的深度为1000,不压缩路径那么这个分支每个节点平均查找次数为500,压缩一次下次再查找就是1次。

学会路径压缩,你基本可以秒杀大部分并查集的题。

代码实现

并查集实现起来较为简单,直接贴代码!代码很久前写的,如果有纰漏还请指出。

import java.util.Scanner;
public class DisjointSet {static int tree[]=new int[100000];//假设有500个值public DisjointSet()    {set(this.tree);}public DisjointSet(int tree[]) {this.tree=tree;set(this.tree);}//初始化所有都是-1 有两个好处,这样他们指向-1说明是自己,//第二,-1代表当前森林有-(-1)个public void set(int a[]){int l=a.length;for(int i=0;i<l;i++){a[i]=-1;}}public int search(int a)//返回头节点的数值{if(tree[a]>0)//说明是子节点{return tree[a]=search(tree[a]);//路径压缩}elsereturn a;}public int value(int a)//返回a所在树的大小(个数){if(tree[a]>0){return value(tree[a]);}elsereturn -tree[a];}public void union(int a,int b)//表示 a,b所在的树合并{int a1=search(a);//a根int b1=search(b);//b根if(a1==b1) {System.out.println(a+"和"+b+"已经在一棵树上");}else {if(tree[a1]<tree[b1])//这个是负数,为了简单减少计算,不在调用value函数{tree[a1]+=tree[b1];//个数相加  注意是负数相加tree[b1]=a1;       //b树成为a的子树,直接指向a;}else{tree[b1]+=tree[a1];//个数相加  注意是负数相加tree[a1]=b1;       //b树成为a的子树,直接指向a;}}}public static void main(String[] args){       DisjointSet d=new DisjointSet();d.union(1,2);d.union(3,4);d.union(5,6);d.union(1,6);d.union(22,24);d.union(3,26);d.union(36,24);System.out.println(d.search(6));    //头System.out.println(d.value(6));     //大小System.out.println(d.search(22));   //头System.out.println(d.value(22));     //大小}
}

结语

并查集属于简单但是很高效率的数据结构。在集合中经常会遇到。如果不采用并查集而传统暴力效率太低,而不被采纳。

另外,并查集还广泛用于迷宫游戏中,下面有机会可以介绍用并查集实现一个走迷宫小游戏。大家欢迎关注!

推荐阅读

 (加强版)大数加减乘除,一文彻底搞定

 花5分钟看这篇之前,你才发现你不懂RESTful

 Java自学方法和路线,我万字推荐你这样学

 栈,就后进先出?

相互吹捧,共同进步,欢迎关注我的公众号:【bigsai】欢迎加个好友【q1315426911】交流,也可拉你进群交流学习,也可做个朋友圈点赞之交!如果感觉有收获还请点赞、在看、分享一波!

各位xdm希望能点个一键三连,小big在这里感激不尽


http://chatgpt.dhexx.cn/article/sdVey2vm.shtml

相关文章

数据结构——并查集

并查集是一种数据结构&#xff0c;是树的一种应用&#xff0c;用于处理一些不交集&#xff08;一系列没有重复元素的集合&#xff09;的合并以及查询问题。并查集支持如下操作&#xff1a; 查询&#xff1a;查询某个元素属于哪个集合&#xff0c;通常是返回集合内的一个“代表…

并查集详解(C/C++)

并查集算法详解&#xff08;C&#xff09; 并查集基础并查集是什么&#xff1f;并查集的作用是什么&#xff1f;并查集的结构合并查询 代码实现优化1&#xff1a;避免退化&#xff08;按秩合并&#xff09;代码优化 优化2&#xff1a;路径压缩代码优化 最终代码实现复杂度分析经…

并查集及其应用

并查集的基本操作: 1.合并两个集合 2.查询两个元素的祖宗节点 扩展: 1.记录每个集合的大小 将集合大小绑定到代表元素节点上 就是并查集的思想 (不是每个元素都是正确的 但是代表元素是正确的) 2.记录每个点到根节点的距离 绑定到每个元素身上 因为每个元素到根节点的距离…

并查集(Union-Find) (图文详解)

文章目录 并查集基础知识定义C实现优化 精选算法题(Java实现)实现并查集交换字符串中的元素最长连续序列 - 字节面试常考连通网络的操作次数最大岛屿数量 (三种解法)省份数量冗余连接冗余连接Ⅱ情侣牵手(困难)移除最多的同行或同列石头等式方程的可满足性 结语 并查集基础知识 …

什么是 “并查集” ?

导语&#xff1a;并查集是一种精巧的算法&#xff0c;本身并不难理解&#xff0c;却很常用&#xff0c;在许多场景下都能找到并查集的身影。 本文作者封承成&#xff0c;年仅12岁&#xff0c;非常感谢他的投稿。 并查集是什么 并查集&#xff0c;是一种判断“远房亲戚”的算法。…

并查集(Disjoint Set)

目录 ❤️什么是并查集&#xff1f; &#x1f3b6;实现方法1 &#x1f414;实现方法2 &#x1f383;题目1 ❤️什么是并查集&#xff1f; 并查集是一种数据结构&#xff0c;用于处理一些不交集&#xff08;Disjoint sets&#xff0c;一系列没有重复元素的集合&#xff09;的…

并查集

参考 https://www.cnblogs.com/asdfknjhu/p/12515480.html https://www.bilibili.com/video/BV13t411v7Fs?p3 https://leetcode-cn.com/problems/number-of-provinces/solution/python-duo-tu-xiang-jie-bing-cha-ji-by-m-vjdr/ 一、基本概念 并查集是一种数据结构 并查集这…

并查集(详细解释+完整C语言代码)

目录 1概论 2.树的表现形式 3.代码实现 3.1创立集合 3.2合并 3.3查询 3.4路径压缩 第一个方法&#xff1a;查找时优化 第二个方法&#xff1a;合并时优化&#xff08;加权标记法&#xff09; 4.完整代码 4.1优化前 4.2优化后 1概论 并查集是一种十分精巧且实用的树形…

时间序列预测的一般步骤

一、ARIMA模型概述 ​​ ARMA模型就是AR和MA的简单结合&#xff0c;同时包含了历史数值项和错误项。由于AR和MA模型都对时间序列有平稳性要求&#xff0c;ARMA模型也存在这个限制&#xff0c;因此我们将其拓展到ARIMA模型&#xff0c;其可以解决非平稳性问题。引入的差分概念是…

时间序列预测算法总结

时间序列算法 time series data mining 主要包括decompose&#xff08;分析数据的各个成分&#xff0c;例如趋势&#xff0c;周期性&#xff09;&#xff0c;prediction&#xff08;预测未来的值&#xff09;&#xff0c;classification&#xff08;对有序数据序列的feature提…

基于深度学习的时间序列预测

# 技术黑板报 # 第十一期 推荐阅读时长&#xff1a;15min 前言 时间序列建模历来是学术和工业界的关键领域&#xff0c;比如用于气候建模、生物科学和医学等主题应用&#xff0c;零售业的商业决策和金融等。虽然传统的统计方法侧重于从领域专业知识层面提供参数模型&#xff0…

预测类问题中的时间序列预测模型

前言&#xff1a;时间序列预测模型适用于含有时间变量的模型预测&#xff0c;对中短期的预测有着较好的结果&#xff0c;对长期预测不适用。本文重点介绍ARIMA模型的原理及代码实现。 其他模型总结&#xff1a;​【Python】Python中的经典时间序列预测模型总结_风度78的博客-C…

Transformer 在时间序列预测中的应用

2017年&#xff0c;Google的一篇 Attention Is All You Need 为我们带来了Transformer&#xff0c;其在NLP领域的重大成功展示了它对时序数据的强大建模能力&#xff0c;自然有人想要把Transformer应用到时序数据预测上。在Transformer的基础上构建时序预测能力可以突破以往的诸…

【推荐收藏】11种比较常用的时间序列预测模型

时间序列及其预测是日常工作中建模&#xff0c;分析&#xff0c;预测的重要组成部分。 本文我们将从0开始介绍时间序列的含义&#xff0c;模型及其分析及其常用的预测模型。 文章目录 交流时间序列定义时间序列预测模型与方法原始数据朴素法简单平均法移动平均法指数平滑法一次…

时间序列预测的20个基本概念总结

1、时间序列 时间序列是一组按时间顺序排列的数据点 比如&#xff1a; 每小时的气压每年的医院急诊按分钟计算的股票价格 2、时间序列的组成部分 时间序列数据有三个主要组成部分。 趋势季节性残差或白噪声 3、趋势 在时间序列中记录的长期缓慢变化/方向。 4、季节性 …

时间序列-预测(Forcasting):时间序列预测算法总结

一、背景介绍 绝大部分行业场景,尤其是互联网、量化行业,每天都会产生大量的数据。金融领域股票价格随时间的走势;电商行业每日的销售额;旅游行业随着节假日周期变化的机票酒店价格等; 我们称这种不同时间收到的,描述一个或多种特征随着时间发生变化的数据,为时间序列…

时间序列预测 | ARMA应用指南

ARMA可谓是时间序列最为经典常用的预测方法&#xff0c;广泛应有于涉及时间序列的各个领域。ARMA模型自出道以来&#xff0c;出场次数不可胜数。想必大家也都不陌生&#xff0c;常学常新&#xff0c;我们今天不妨再来回顾一遍&#xff5e;。 ARMA全称Autoregressive moving ave…

时间序列预测的7种方法

import pandas as pd#取数 #dfpd.read_csv(jetrail.csv) #print(df.head()) ID Datetime Count 0 0 25-08-2012 00:00 8 1 1 25-08-2012 01:00 2 2 2 25-08-2012 02:00 6 3 3 25-08-2012 03:00 2 4 4 25-08-2012 04:00 2#pr…

Transformer时间序列预测

介绍&#xff1a; 提示&#xff1a;Transformer-decoder 总体介绍 本文将介绍一个 Transformer-decoder 架构&#xff0c;用于预测Woodsense提供的湿度时间序列数据集。该项目是先前项目的后续项目&#xff0c;该项目涉及在同一数据集上训练一个简单的 LSTM。人们认为 LSTM 在…

时间序列预测的8种常用方法简介

时间序列预测的7种方法 1. 朴素预测法&#xff08;Naive Forecast) 如果数据集在一段时间内都很稳定&#xff0c;我们想预测第二天的价格&#xff0c;可以取前面一天的价格&#xff0c;预测第二天的值。这种假设第一个预测点和上一个观察点相等的预测方法就叫朴素法&#xff…