并查集

来源:互联网 发布:java 深拷贝工具类 编辑:程序博客网 时间:2024/04/30 00:48

-----------------siwuxie095

  

  

  

  

  

  

  

  

并查集基础

  

  

这里介绍并查集(Union Find),它是一种很不一样的树形结构

  

  

  

并查集的作用:可以非常高效地回答连接问题

  

「连接问题,即Connection Problem」

  

  

  

首先简单的采用可视化的方式来看连接问题,如下:

  

  

  

在上图中有若干个点,点与点之间有可能相连

  

  

有这么一个问题:某两个点是不是连接在一起

  

如果这两个点比较近,通过这张图就可以非常容易看出来,它们是否

连接在一起

  

如果这两个点比较远,比如:左上角的点和右下角的点,只是通过人

眼来看这张图,就很难非常快速地回答这个问题

  

  

那么在这种情况下,就需要使用计算机,可是计算机如何高效地回答

这个问题呢?并查集这种数据结构就提供了一个非常好的解决方案

  

  

  

可能有人会问,在这样一张图判断两个点是否连接在一起,意义何在?

  

事实上,这只是一个抽象的问题的模型表述。连接问题在实际应用中

有着非常重要的作用

  

  

  

  

  

  

  

连接问题

  

  

连接问题最主要的一个作用就是可以判断网络中节点间的连接状态

  

注意:这里的网络是一个非常抽象的概念,并不一定就具体的代表

计算机网络

  

  

  

如:一个大型的社交网络,也是网络,即用户之间形成的网络

  

FaceBook 中,用户和用户之间形成了好友的关系。那么这个好友的关系,

就是一种连接的关系,FaceBook 有很多用户,他们之间通过这种好友关系

的连接,就形成了一个巨大的网络

  

那么在FaceBook 中就能问这样一个问题:任意的两个人A 和 B,他们之间

是否能够通过好友直接互相认识?这就是一个典型的连接问题

  

  

  

当然,网络不仅仅包含用户之间形成的社交网络,一个巨大的数据库中

有很多的音乐、电影、书籍这些多媒体之间也可以形成网络

  

更不用提互联网的网页之间,本身形成的也是网络,路由器和路由器之间

的数据交换形成的也是网络,另外还有道路交通、航班调度这些全部

可以形成网络

  

那么在这些网络中,都可以使用并查集来回答类似的连接问题

  

  

  

  

  

  

  

集合

  

  

并查集还有另外一个非常重要的作用,就是可以实现数学中的集合

  

「数学中的集合类实现」

  

通过并查集的名字,大概也能看出来,并查集的,其实就是实现

一个并集的意思

  

所以,在使用数学中集合的思路解决问题时,如果经常使用并集操

作,同时需要查询元素在集合中的状态的话,并查集也是一个非常

好的选择

  

  

  

  

  

  

  

路径问题

  

  

可能有人看到了连接问题,就会想到一个相应的问题,叫做路径问题

  

  

熟悉算法的人都会知道,经常会有这样的问题:这些节点之间既然已经

能够连接了,那么能不能从一个节点通过一条路径到达另外一个节点?

  

路径问题,在图论中会有所涉及

  

  

  

  

  

  

  

连接问题与路径问题

  

  

连接问题和路径问题的区别:连接问题路径问题回答的问题要少

  

  

不难想象,路径问题直接求出了两个节点之间连接的路径,具体是什

么,而连接问题只需要回答两个节点之间是否相连就够了

  

  

正因为连接问题回答的问题比路径问题少,所以能设计出更快的算法

来解决连接问题,而不求出两个节点之间具体的路径

  

  

  

  

  

事实上,在计算机算法领域,经常会遇到类似的问题,即并不需要回答

那么多问题,也正因为如此,可以设计出更高效的算法

  

如下:

  

1)和二分查找作比较

  

现在要在一个有序数组中查找一个元素,可以使用二分查找法,也可以

使用顺序查找法

  

其中,二分查找法是O(lgn)的复杂度,顺序查找法是O(n)的复杂度

  

为什么顺序查找法会更慢一些呢?

  

一个更重要的原因就是:顺序查找法不仅查找到了这个元素,顺序查找

法还找到了这个元素在整个数组中的排名。也就是说,顺序查找法顺便

回答了rank这个问题

  

不仅如此,顺序查找法还把查找到的这个元素之前的所有元素的排名,

全部顺道求了出来,只不过我们不关心,所以没有存储,但是这个过

程都遍历了一遍。所以,二分查找法更高效

  

  

  

2)和select 作比较

  

现在要在任意一个数组中找出排名第n 的元素,可以使用快速排序的

partition 的思路,设计出一个 select 算法。不过对于这种问题,一

个更直观的想法是:可以直接把这个无序数组排一遍序,当排好序之

后,就能直接找到排名为n 的元素

 

其中,使用快排的思路实现的 select,是O(n) 级别的复杂度,而先

排序再求出排名第n 的元素,是O(n*lgn)的复杂度

  

为什么排一遍序会更慢一些呢?

  

一个更重要的原因,就是排好序以后,不仅能够回答排名第n 的元素

是多少,还能回答排名是 n-1 的元素是多少,n-2 的元素是多少 …

  

事实上,可以回答排名第x 的元素是多少(0 <= x <= n)

  

也就是说,排好序之后,能够回答的问题更多。而使用快排的思路实

现的select,能够回答的问题相对少一些,也正因为如此,这个算法

更高效

  

  

  

3)和作比较

  

用堆这种数据结构,可以非常快速的找出数据中的最大值和最小值

  

堆这种数据结构之所以高效,也是因为在问题模型中,我们只关心

最大值最小值,不关心第二名、第三名

  

正是应用了这样的性质,设计出了堆这种高效的数据结构

  

  

  

  

 

所以,当针对一个某问题设计出一个算法后,不妨问问自己,我们

所实现的这个算法除了回答了问题本身之外,是不是额外回答了一

些别的问题

  

如果我们的算法额外回答了一些别的问题,那么很有可能存在一个

更高效的算法。它之所以高效,正是因为它没有回答额外问题

  

  

  

  

  

  

  

  

  

【made by siwuxie095】

原创粉丝点击