【C++实现】并查集 6个版本 从入门到优化

#ifndef __UF__H__
#define __UF__H__
#include<cassert>

//只记录id值,和哪个节点联通,效率最低
class UF1
{
private:
	int *id;
	int count;
public:
	UF1(int n){
		count = n;
		id = new int[n];
		for (size_t i = 0; i < n; i++){
			id[i] = i;
		}
	}
	~UF1(){
		delete[] id;
	}

	int find(int p){
		assert(p < count && p>=0);
		return id[p];
	}
	bool isConnected(int p, int q){
		return find(p) == find(q);
	}
	void unionElement(int p, int q){
		int pId = find(p);
		int qId = find(q);
		if (pId == qId) return;

		for (size_t i = 0; i < count; i++){
			if (id[i] == pId)
				id[i] = qId;
		}
	}
};

//id改为指向父节点,只需判断两个节点根节点是否相同,没考虑每个节点的高度,效率低
class UF2
{
private:
	int *parent;
	int count;
public:
	UF2(int n){
		count = n;
		parent = new int[n];
		for (size_t i = 0; i < n; i++){
			parent[i] = i;
		}
	}
	~UF2(){
		delete[] parent;
	}

	int find(int p){
		assert(p < count && p >= 0);
		while (p!=parent[p]){
			p = parent[p];
		}
		return p;
	}
	bool isConnected(int p, int q){
		return find(p) == find(q);
	}
	void unionElement(int p, int q){
		int pRoot = find(p);
		int qRoot = find(q);
		if (pRoot == qRoot) return;
		parent[pRoot] = qRoot;
	}
};

//基于每个节点的数据规模来优化,效率高,但可能出现极端情况
class UF3
{
private:
	int *parent;
	int *sz;
	int count;
public:
	UF3(int n){
		count = n;
		parent = new int[n];
		sz = new int[n];
		for (size_t i = 0; i < n; i++){
			parent[i] = i;
			sz[i] = i;
		}
	}
	~UF3(){
		delete[] parent;
		delete[] sz;
	}

	int find(int p){
		assert(p < count && p >= 0);
		while (p != parent[p]){
			p = parent[p];
		}
		return p;
	}
	bool isConnected(int p, int q){
		return find(p) == find(q);
	}
	void unionElement(int p, int q){
		int pRoot = find(p);
		int qRoot = find(q);
		if (pRoot == qRoot) return;
		if (sz[pRoot] < sz[qRoot]){
			parent[pRoot] = qRoot;
			sz[qRoot] += sz[pRoot];
		}
		else{
			parent[qRoot] = pRoot;
			sz[pRoot] += sz[qRoot];
		}
	}
};

//基于每个节点的高度来优化,效率高,避免极端情况
class UF4
{
private:
	int *parent;
	int *rank;
	int count;
public:
	UF4(int n){
		count = n;
		parent = new int[n];
		rank = new int[n];
		for (size_t i = 0; i < n; i++){
			parent[i] = i;
			rank[i] = i;
		}
	}
	~UF4(){
		delete[] parent;
		delete[] rank;
	}

	int find(int p){
		assert(p < count && p >= 0);
		while (p != parent[p]){
			p = parent[p];
		}
		return p;
	}
	bool isConnected(int p, int q){
		return find(p) == find(q);
	}
	void unionElement(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[pRoot] > rank[qRoot]){
			parent[qRoot] = pRoot;
		}
		else{
			parent[pRoot] = qRoot;
			rank[qRoot] += 1;
		}
	}
};

//路径压缩,在查找根节点的过程中,让节点的父节点指向父节点的父节点,可跳过一步查找,实际效率最高
class UF5
{
private:
	int *parent;
	int *rank;
	int count;
public:
	UF5(int n){
		count = n;
		parent = new int[n];
		rank = new int[n];
		for (size_t i = 0; i < n; i++){
			parent[i] = i;
			rank[i] = i;
		}
	}
	~UF5(){
		delete[] parent;
		delete[] rank;
	}

	int find(int p){
		assert(p < count && p >= 0);
		while (p != parent[p]){
			parent[p] = parent[parent[p]];
			p = parent[p];
		}
		return p;
	}
	bool isConnected(int p, int q){
		return find(p) == find(q);
	}
	void unionElement(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[pRoot] > rank[qRoot]){
			parent[qRoot] = pRoot;
		}
		else{
			parent[pRoot] = qRoot;
			rank[qRoot] += 1;
		}
	}
};

//路径压缩,在查找根节点的过程中,递归让每个节点的父节点均指向根节点,理论效率最高,但递归过程耗时,实际可能比上一个版本的路径压缩效率低
class UF6
{
private:
	int *parent;
	int *rank;
	int count;
public:
	UF6(int n){
		count = n;
		parent = new int[n];
		rank = new int[n];
		for (size_t i = 0; i < n; i++){
			parent[i] = i;
			rank[i] = i;
		}
	}
	~UF6(){
		delete[] parent;
		delete[] rank;
	}

	int find(int p){
		assert(p < count && p >= 0);
		if (p != parent[p]){
			parent[p] = find(parent[p]);
		}
		return parent[p];
	}
	bool isConnected(int p, int q){
		return find(p) == find(q);
	}
	void unionElement(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[pRoot] > rank[qRoot]){
			parent[qRoot] = pRoot;
		}
		else{
			parent[pRoot] = qRoot;
			rank[qRoot] += 1;
		}
	}
private:

};
#endif

 

#include"UF.h"
#include<iostream>
#include<ctime>
using namespace std;
template<typename Item>
void testTime(Item* uf, int n){
	srand(time(NULL));

	time_t startTime = clock();

	for (int i = 0; i < n; i++){
		int a = rand() % n;
		int b = rand() % n;
		uf->unionElement(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 << "\t" << 2 * n << " ops, " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl;
}
template<typename Item>
void testUF(int n){
	Item *uf1 = new Item(n);
	
	testTime(uf1, n);

	delete uf1;

}

int main(){

	cout << "testUF1" << endl;
	testUF<UF1>(10000);

	cout << "testUF2" << endl;
	testUF<UF2>(10000);
	 
	cout << "testUF3" << endl;
	testUF<UF3>(1000000);

	cout << "testUF4" << endl;
	testUF<UF4>(1000000);

	cout << "testUF5" << endl;
	testUF<UF5>(1000000);

	cout << "testUF6" << endl;
	testUF<UF6>(1000000);

	system("pause");
	return 0;
}

测试效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值