并查集的常规实现方法

在上一节中,我们讨论了并查集的简单实现方法,然而我们却发现并查集的效率好像并不是很高,因此,计算机科学家想出了另外一种方法来实现并查集。

并查集的常规实现方法_第1张图片

在新的实现思路中,我们把每一个元素看做是一个节点,该节点只有一个指向其父亲的指针,也就是说parent[i]=j的意思就是i元素的父亲为j元素,因为 i 元素的父亲指针就是指向 j 节点的,如果一个元素没有父亲了,那么它的父亲指针就指向自己,这也是作为根节点的一个标志。

并查集的常规实现方法_第2张图片


如上图所示,对于2元素,他的父亲指针是指向自己的,也就是说2元素是这个集合的根,我们可以把结合理解为一个家族,位于同一个人家族的人他们的祖宗肯定是同一个人的,类比成并查集的话,也就是所位于同一个集合中的元素其根节点都是同一个节点的,在上图中,最开始(5,6,7)为一个集合,(2,3)为一个集合,(1)为一个集合,

如果我们需要把1元素与3元素各自相应所在的集合合并的话,我们该怎么办呢?

我们可以类比成两个家族,如果两个不同的家族要合并成为一个家族的话,也就是两个家族的祖先必须是一样的,因此,我们只需要任意选一个家族的祖先,让该祖先的父节点由指向其自己改为指向另一个家族的祖先,这样两个家族的所有的成员的祖先就是同一个人元素了,我们也完成了两个家族的合并。

转换成并查集来说,就是把一个集合的根节点的父节点指向其另一个集合的根节点。这样就完成了Union操作。

对于上图来说,要把三个集合合并成为一个集合,我们只需要把5元素(根元素)的父亲指针指向2元素(根元素),把1元素(根元素)的父亲指针指向2元素(根元素)就好了。

并查集的常规实现方法_第3张图片

如上图所示,这是一个通过上述方法已经完成了合并操作的并查集,通过partent[i]可以查到 i 元素的父亲节点,然后parent[父亲节点]又能够了解到父亲节点的父亲节点,一直到根元素位置。

另外:根元素的父亲指针指向其自己。

  

  让我们来看一下具体的代码实现:

 //找出元素p位于的集合的编号
        //即返回根元素
        int find(int p){
             assert(p>=0&&p

接下来我们测试一下第二版本的并查集执行2万次操作的时间对比:


我们发现,UF2的效率要高出UF1,我们接下来测试20万次操作的时间对比:


貌似当数据量很大时,UF2并没有体现出很大的优化力度。

因此,我们需要对这一版本的并查集还要继续优化。

第二版本的完整源代码请点此此处访问。



你可能感兴趣的:(数据结构与算法)