随笔- 509  文章- 0  评论- 151  阅读- 22万 

2014.06.18 14:16

简介:

  “并查集”,英文名为“union-find set”,从名字就能看出来它支持合并与查找功能。另外还有一个名字叫“disjoint set”,中文名叫不相交集合。可能我们倾向于用最短的名字,所以就出现了“并查集”翻译为“disjoint set”的情况。并查集是一种树形结构,但与之前讲的树不同的是,这里的树节点只记录父节点,因此是一对一的,就可以用数组来表示并查集。

图示:

  并查集可以认为是一个“森林”,也就是多棵树:

  

  既然是并查集,先看看合并3和5之后结果如何:

  

  那么3和5岂不是父子关系了?不是。我们关心的不是谁是父谁是子,而是3和5现在在一起了。下面这样效果是一样的:

  

  这个看起来不像树形结构啊?那就来个节点个数更多的例子:

  

  再看看查找操作:

  

  这样的查找操作不改变树的形状,自底向上,复杂度必然是O(H),也就是和树的高度成正比。有什么坏处呢?

  

  路径压缩可以通过让树变得更扁来降低高度,从而加速查找操作。首先仍然是查找:

  
  然后依次把沿路的所有节点直接挂到根节点上:

  

  

  

  图片占的篇幅更少,显然是因为树变矮了。现在查找操作只需要O(1)时间了。

  那么并查集有什么用呢?通俗地说,是用来判断一群人中,谁和谁是一伙儿的,谁和谁不是。不通俗地说,可以看看“等价关系”、“等价类”的一些集合论的资料,从中寻找一些理论支持。

  在此给出一道用并查集解决的ZOJ简单题:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2833

实现:

复制代码
 1 // My implementation for  disjoint set.
 2 #include <vector>
 3 using namespace std;
 4 
 5 int findRoot(const vector<int> &dj, int x)
 6 {
 7     int k, r;
 8     
 9     r = x;
10     while (r != dj[r]) {
11         r = dj[r];
12     }
13     
14     k = x;
15     while (k != r) {
16         x = dj[x];
17         dj[k] = r;
18         k = x;
19     }
20     
21     return r;
22 }
23 
24 void unionSet(vector<int> &dj, int x, int y)
25 {
26     int n = (int)dj.size();
27     
28     if (x == y) {
29         return;
30     }
31     
32     dj[x] = y;
33     findRoot(x);
34 }
35 
36 int main()
37 {
38     return 0;
39 }
复制代码

 

 posted on   zhuli19901106  阅读(1939)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示