Fork me on GitHub

Quick Find

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

   

   

   

   

   

   

   

   

Quick Find

   

   

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

   

   

   

对于一组数据,并查集主要支持两个操作:

   

1union( p , q ),即 ,将 p 和 q 两个元素合并在一起,也就是所谓的连接

   

2find( p ),即 ,查找 p 元素具体在哪个集合中

   

   

   

有了这两个操作,使用并查集也可以轻易地回答这样一个问题:

   

isConnected( p , q ),传入 p 和 q 两个元素,判断两个元素是否相连接

   

   

   

并查集的基本数据表示

   

对于如上需求,最简单的数据表示方式就是数组,其中:数组的索引

用来表示元素

   

如果有 0-9,共 10 个元素,这些元素之间连接关系的表示方法如下:

   

「即 给每一个元素都赋上一个值」

   

1

   

   

   

0-4 对应的值都是 0,而 5-9 对应的值都是 1。表示 0-4 这 5 个

元素之间是互相连接的,而 5-9 这 5 个元素之间是互相连接的

   

   

   

2

   

   

   

02468 对应的值都是 0,而 13579 对应的值都

1。表示 5 个偶数和 5 个奇数是分别互相连接的

   

   

   

不妨给这个数组起一个名字,叫做 id,即 所有连接在一起的元素,

它们都具有相同的 id

   

   

   

   

   

程序:Quick Find 的实现

   

UnionFind.h:

   

#ifndef UNIONFIND_H

#define UNIONFIND_H

   

#include <iostream>

#include <cassert>

using namespace std;

   

   

   

//并查集:Quick Find

namespace UF

{

   

class UnionFind

{

   

private:

int *id;

int count;

   

public:

UnionFind(int count)

{

this->count = count;

id = new int[count];

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

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

{

id[i] = i;

}

}

   

   

~UnionFind()

{

delete []id;

}

   

   

//找到每一个元素所集合的id:直接访问id相应的值即可

//称这种实现为 Quick Find,也就是Find操作非常快,

//只需要使用O(1)的时间复杂度就够了

int find(int p)

{

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

return id[p];

}

   

   

//回答两个元素是否相互连接的问题:id相同则相互连接

bool isConnected(int p, int q)

{

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

}

   

   

//Quick Find下的Union操作的时间复杂度 O(n)

//(因为unionC++中是关键字,所以不能把函

//数名起成union

void unionElements(int p, int q)

{

   

int pID = find(p);

int qID = find(q);

   

if (pID == qID)

{

return;

}

   

//Union操作是将两个元素所在集合全部并在一起,而不是只将 p 元素

//并到 q 元素所在集合,或只将 q 元素并到 p 元素所在集合

//

//这样,本来两个元素所在集合的所有元素,两两之间就互相连接了

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

{

//或者反向亦可

if (id[i] == pID)

{

id[i] = qID;

}

}

   

}

};

}

   

   

#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;

}

}

   

   

//由于单个Union操作的时间复杂度是O(n)级别的,所以执行nUnion操作,

//时间复杂度就是O(n^2)级别的

//

//而在查看是否连接isConnected()的复杂度是O(1),执行n个操作,就是O(n)

//

//不过整体上,此次测试的复杂度是O(n^2)级别的

//

// Quick Find,它查找(Find)的速度非常快,可是在执行并(Union)这个

//操作的时候,效率却不尽人意

   

#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 15:54  siwuxie095  阅读(271)  评论(0编辑  收藏  举报

导航