Quick Union

来源:互联网 发布:arduino json 编辑:程序博客网 时间:2024/06/11 02:42

-----------------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 =newint[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");

return0;

}

  

  

运行一览:

  

  

  

  

  

  

  

  

  

  

【made by siwuxie095】

原创粉丝点击