【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
#include <iostream>
#include <cassert>
#include <ctime>
using namespace std;
/**
一句箴言: 为每个元素指定父ID,默认指向自己,当要相连时则将ID指向另外一个元素。看两元素是否能连接的标准为各自指向的根是否一样。(看祖老先人是否一样)
方法:合并指向的时候通过size个数或者rank层数来继续优化指向。rank层数更优
**/
class UnionFind {
private:
int *parent;
int *sz;//sz[i] 表示以i为根的集合中元素的个数
int *rank;//rank[i] 表示以i为根的集合所以表示的层数
int count;
public:
UnionFind(int count) {
this->count = count;
parent = new int[count];
sz = new int[count];
rank = new int[count];
for(int i = 0; i < count; i++) {
parent[i] = i;
sz[i] = 1;
rank[i] = 1;
}
}
~UnionFind() {
delete [] parent;
delete [] sz;
delete [] rank;
}
//寻找元素对应的根
int find(int p) {
assert(p >= 0 && p <count);
while(p != parent[p])
p = parent[p];
return p;
}
//根据元素对应的根是否相同来判断是否能连接
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;
//拥有层数少的根指向层数多的根。原因是为了防止随意指向后层数过多
if (rank[pRoot] < rank[qRoot]){
parent[pRoot] = qRoot;
}else if (rank[qRoot] < rank[pRoot]){
parent[qRoot] = pRoot;
} else{
parent[qRoot] = pRoot;
rank[pRoot] += 1;
}
//拥有元素少的根指向元素多的根。原因是为了防止随意指向后元素过多
// if (sz[pRoot] < sz[qRoot]) {
// parent[pRoot] = qRoot;
// sz[qRoot] += sz[pRoot];
// } else {
// parent[qRoot] = pRoot;
// sz[pRoot] += sz[qRoot];
// }
}
void printIds() {
for(int i = 0; i < count; i++) {
cout << parent[i] << " ";
}
}
};
int main() {
time_t startTime = clock();
int n = 100000;
UnionFind uf = UnionFind(n);
srand(time(NULL));
for(int i= 0; i < n; i++ ) {
int a = rand() % n;
int b = rand() % n;
uf.unionElements(a, b);
}
for(int i = 0; i < n; i++) {
int a = rand() % n;
int b = rand() % n;
uf.isConnected(a, b);
}
time_t endTime = clock();
cout << double(endTime-startTime)/CLOCKS_PER_SEC<<" s"<<endl;
// uf.printIds();
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/214052/blog/3152398