并查集之通过根节点实现

邮差的信 提交于 2020-01-06 18:19:09

【推荐】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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!