并查集讲解
- 一、算法描述
- 二、图示讲解
- 三、代码示例
- 四、例题练习
一、算法描述
并查集算法是一种用于处理不相交集合数据结构的算法。它经常被用来解决网络流问题、图的最小生成树问题等。在这篇博客中,我们将深入理解并查集算法,以及如何在实际编程中使用它。
首先,我们需要了解什么是并查集。并查集是一种数据结构,它可以用于管理一组不相交的集合。每个集合由一个根节点表示,集合中的所有其他节点都是该根节点的子节点。并查集的主要操作是合并和查找。
合并操作将两个集合合并成一个集合。查找操作返回给定元素所属的集合的根节点。
并查集的实现通常使用路径压缩和union by rank策略。路径压缩策略在查找操作时立即缩短元素到根节点的路径。union by rank策略在合并操作时使合并后的集合的根节点具有更高的优先级。
二、图示讲解
- 如图所示,有初始7个节点如下所示:
- 已知给出一个无向图的几条边:[0,2],[0,5],[2,4],[1,6],[5,4],原始无向图如下图所示。
- 现在根据并查集算法合并调整图结构,更直观的给出哪些点对可以到达。
- 首先按顺序处理给定的边集,先处理【0,2】.查找0和2的祖先节点,然后比较两者祖先节点的权重大小。这里0和2的祖先节点是本身,且当两者的秩相同,以右侧节点为父节点(个人习惯)。此时节点0的权重为1,节点2的权重为2。我这里权重指的是包括自身在内的子节点数
- 处理边【0,5】:先查找0的祖先节点为2,其权重为2 。5的祖先节点为5,权重1 。所以比较2和5的权重,因此将5添加为2的子节点。
- 处理【2,4】:2的祖先节点为2,权重为3,4的祖先节点为4,权重为1 。故将4添加到2的子节点
- 处理【1,6】:1的祖先节点为1,权重为1. 6的祖先为6,权重为1 。将1添加为6的子节点
- 处理【5,4】:5的祖先节点为2,4的祖先节点为2,当两者祖先节点相同时,不进行合并操作。
- 所以最终的节点图如下所示:
此时,各集合处理完毕,如果要求不可到达点对数,就可以根据各集合根节点的权重也就是包括自身在内节点数进行计算,上面的例子中的不可到达点对数为:4×2 + 4×1 + 1*2 = 14
三、代码示例
接下来,我们将看一个简单的并查集的Java实现:
class UnionUtil{//用来存储图的结点public int [] arrays ;//存储节点的深度public int [] sizes;//构造方法,根据节点个数进行初始化public UnionUtil(int n){init(n);}//初始化方法public void init(int n){arrays = new int[n];sizes = new int[n];for(int i = 0 ; i<n ; i++){arrays[i] = i;sizes[i] = 1;}}//查找节点的祖先节点,及根节点public int find(int i){if(arrays[i] == i){return i;}else{// 压缩路径,直接将节点指向根节点arrays[i] = find(arrays[i]);return arrays[i];}}//合并节点public void union(int x,int y){int a = find(x),b = find(y);if(a != b){//比较根节点的深度,将深度小的添加到深度高的if(sizes[a] = sizes[b]){arrays[b] = a;sizes[a] += sizes[b];}else{arrays[a] = b;sizes[b] += sizes[a];}}}//获取节点的深度public int getSize(int x){return sizes[x];}
}
在这个实现中,find
函数用于查找元素的根节点,union
函数用于合并两个集合。arrays
列表存储每个元素的根节点,size
列表存储每个根节点的优先级。
四、例题练习
leetcode-2316. 统计无向图中无法互相到达点对数