咳咳,刚看完海贼更新,马上呼哧呼哧写下这篇文章,这周的目标就是出一篇并查集相关的文章,真的是时间咻咻一下就没了。
本文阅读大概需要3分钟。 好了,并查集呢,英文叫Union-Find , 并查集是一种树型的数据结构,通常来用于处理一些不相交集合的合并(Union)问题,以及查询(Find)问题。 如下: 1 : 有两个区域 Area 1 和 Area 2 2 : 每个区域里面,每个子节点只可以给父节点打电话,根节点给自己打电话. 例如Area1中,D可以打给B,B可以打给A,A可以打给自己 (A:我就是要自己打自己 ^-^ ) 那么问题来了,如果D要给E通信,要经过多少步呢?
int maxNum = ...;// 存储每个节点的父节点,例如 nodeA 的父节点就是pre[NodeA]Node pre[maxNum];// find 函数,查找根节点// 递归版本private Node find(Node node){ if(pre[node] == node) return node; return find(pre[node]);}// 循环版本private Node find(Node node){ while(node != pre[node]) node = pre[node]; return node;}
find 函数比较简单,当然一般还会伴随有路径压缩 。举个栗子,当你的手机非常多的时候,树的深度就会非常深,那么查找耗时会比较大。路径压缩指的是:
让每个子节点的父节点都直接是根节点 , 如下:
private Node find(Node node){ Node root; Node temp = node; while(node != pre[node]) node = pre[node]; root = node; // 找到 root 了 while(temp != root) { // 开始路径压缩 Node k = pre[temp]; // 将temp的父节点赋值给临时变量 pre[temp] = root; // 将temp的父节点变成根节点root temp = k; // 对 temp 的父节点继续路径压缩 } return root; // 返回根节点}
既然可以找到根节点了,那么根节点A要给E通信就简单了,那就是合并(Union)了 :
// A:根节点A E:根节点 Eprivate void join(Node A,Node E) { pre[A] = E;}
对的,就是这么一步,将 Area1 和 Area2 连接起来,所以D就可以和E通信了。换一下另一个场景,村庄A里面的某一户要到村庄B,那么这一户到村庄A的村头之后,只需要再修一条路到B,就可以到B了。 回到上面的问题,A到E通信需要多少步呢? 如果每到一个节点算一步,那么就是查找以及合并的步数加起来就是啦,这里就不给出代码了。 并查集操作作为比较常见的算法,在geeksforgeeks上也挺多相关的问题,例如
岛屿问题、
字符串转换等,更多可以在这里学习巩固下:
https://www.geeksforgeeks.org/tag/union-find/
当然在leetcode上也是挺多的,搜索对应的tag就能找到,好了水文到此结束,很简单的一篇文章,over . 周末愉快。