Fork me on GitHub

Quick Union

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

   

   

   

   

   

   

   

   

Quick Union

   

   

这里介绍并查集的另外一种实现思路:Quick Union

 

这种实现思路通常是并查集的常规实现思路,而且它的时间效率非常高

   

   

   

具体表示:将每一个元素,都看做是一个节点

   

不过这个节点和树中的节点稍有不同,树中节点的指针是指向自己的孩子,

而并查集中节点的指针却是指向自己的父亲

   

所以在并查集中,就有可能存在这样的一种情况:元素 3 有一个指针指向

元素 2,即 2 是父节点,3 是子节点,这就代表了 2 3 互相连接

   

另外,对于元素 2 来说,如果它本身已经是根了的话,它的指针只要指向

自己就好了,如下:

   

   

   

   

在上面的基础上,如果有元素 1 想和 2 3 连接,就应该将 1 指向父亲

的指针指向 2 3 组成的这棵树的根节点,也就是 2,如下:

   

   

   

   

在上面的基础上,再加另外一个集合 567

   

   

   

   

如果想让元素 5 和元素 2 连接在一起,只需要让 5 相应的指针指向 2 即可

   

   

   

   

另外,如果不是想让元素 5 和元素 2 连接在一起,而是想让元素 7

元素 3 连接在一起,那么最终所形成的树,依然是上图所示的样子

   

这是因为 7 所在的树的根是 53 所在的树的根是 2,所以依然是将 5

2 连接在一起,即让 5 的指针指向 2

   

   

   

   

   

具体在数据表示上,虽然之前使用的一直是指针这个词,但由于每个

元素只要单独存储一个变量,即 父亲具体是哪个元素即可

   

所以在这里,依然使用数组来表示

   

   

   

称这个数组为 parent,parent[i] 就表示元素 i 所指向的父亲元素

   

初始化时,parent[i] = i,即 每个元素的父亲元素都指向自己

   

   

   

   

 

程序:Quick Union 的实现

   

UnionFind.h:

   

#ifndef UNIONFIND_H

#define UNIONFIND_H

   

#include <cassert>

using namespace std;

   

   

   

//并查集:Quick Union

namespace UF

{

   

class UnionFind

{

   

private:

int *parent;

int count;

   

public:

UnionFind(int count)

{

parent = new int[count];

this->count = count;

//在初始情况下,并查集里的元素,两两之间互不连接

for (int i = 0; i < count; i++)

{

parent[i] = i;

}

}

   

   

~UnionFind()

{

delete []parent;

}

   

   

int find(int p)

{

assert(p >= 0 && p < count);

//不断通过p来追溯它的父亲,直到p等于自己的父亲,

// p 节点已经成为了根节点,直接 return 即可

//(即 返回的是p所在集合的根节点)

while (p != parent[p])

{

p = parent[p];

}

   

return p;

}

   

//pq二者是否对应同样的根,来判断它们是否连在一起

//pq的根节点如果相同,则相连)

bool isConnected(int p, int q)

{

return find(p) == find(q);

}

   

   

void unionElements(int p, int q)

{

   

int pRoot = find(p);

int qRoot = find(q);

   

if (pRoot == qRoot)

{

return;

}

   

//互换亦可

parent[pRoot] = qRoot;

}

};

}

   

   

#endif

   

   

   

UnionFindTestHelper.h:

   

#ifndef UNIONFINDTESTHELPER_H

#define UNIONFINDTESTHELPER_H

   

#include "UnionFind.h"

#include <iostream>

#include <ctime>

using namespace std;

   

   

   

namespace UnionFindTestHelper

{

   

void testUF(int n)

{

//设置随机种子

srand(time(NULL));

UF::UnionFind uf = UF::UnionFind(n);

   

time_t startTime = clock();

   

//先进行n次的并,即 Union 操作

for (int i = 0; i < n; i++)

{

int a = rand() % n;

int b = rand() % n;

uf.unionElements(a, b);

}

   

//再进行n次的查,即 Find 操作

for (int i = 0; i < n; i++)

{

int a = rand() % n;

int b = rand() % n;

uf.isConnected(a, b);

}

   

time_t endTime = clock();

   

//打印2*n个操作耗费的时间

cout << "UF, " << 2 * n << " ops, " << double(endTime - startTime) / CLOCKS_PER_SEC

<< " s" << endl;

}

}

   

   

#endif

   

   

   

main.cpp:

   

#include "UnionFindTestHelper.h"

#include <iostream>

using namespace std;

   

   

   

int main()

{

//规模是十万

int n = 100000;

   

UnionFindTestHelper::testUF(n);

   

system("pause");

return 0;

}

   

   

运行一览:

   

   

   

   

   

   

   

   

   

   

【made by siwuxie095】

posted on 2017-06-13 16:06  siwuxie095  阅读(235)  评论(0编辑  收藏  举报

导航