超级详细的基础算法和数据结构合集:
https://blog.csdn.net/GD_ONE/article/details/104061907
摘要
本文主要介绍并查集和其效率最高并且最简单的实现方式。
什么是并查集
并查集顾名思义,是一种用于处理集合与集合之间查询和合并等操作的数据结构。比如询问两点是否在同一集合,将两个不同集合合并等
并查集的实现
给出n个点,将其划分为两个集合,查询其中某两个点是否在同一集合内,你会怎么做?
简单的方法就是,将同一个集合内的所有点设置一个标记,然后查询两个点的标记是否一样。其实这就是并查集了:
-
首先开一个数组, 存n个点
int p[N];
-
刚开始每个点都在不同的集合,所以初始化让每个点都指向自己
for(int i = 1; i <= n; i++) p[i] = i; //并查集初始化
-
那么让两个不用的集合合并呢?很简单,让其中一个点指向另一个点
p[a] = b; // 将a连接到b所在的集合内 或者 //p[b] = a; //将b连接到a所在的集合内
-
那么问题来了,直接让p[a] = b, 那查询的时候肯定会出错的,因为每个点所指向的点都不一样,前面说了,要将同一个集合内的点指向同一个标记,所以p[a] 指向的点应该是b的标记,也就是p[b]的父节点。
也就是p[a] = p[b];但是如果b指向不是那个标记,也就是最终的父节点,这时就又出错了。所以我们要让每个点都指向最终的父结点,也就是那个标记。所以我们要先找到父节点。某一个点指向自己,那么它就是父节点,其他点均指向它。
此find函数是并查集的精髓所在
public static int find(int x){
if(p[x] != x) p[x] = find(p[x]);// p[x] != x 说明p[x]指向的不是父节点
return p[x]; // 在搜索父节点的同时更新p[x]让其指向父节点
}
图示:
这时应该让4指向3 而不是否则查询2,4是否在同一个集合肯定会出错的
所以,find很重要,不能写错了。
并查集有很多种用途,还有很多扩展。这里只介绍并查集是什么,以及最简单的实现方式。