并查集基本实现

并查集的基本实现  和 size优化&路径压缩

#include <iostream>
#include <ctime>
#include <cassert>

#define FOR(n) for( int i = 0 ; i < n ; i ++ )
using namespace std;

//朴素的并查集
class UnionFind{

private:
	int* id;
	int count;
public:
	UnionFind( int n ){
		id = new int[n];
		this->count = n;
		for( int i = 0 ; i < n ; i ++ )
			id[i] = i;
	}
	~UnionFind(){
		delete[] id;
	}
	//查找p的组
	int find( int p ){
		assert( p >= 0 && p < count );
		return id[p];
	}
	//查看p和q是否在一组
	bool isConnected( int p , int q ){
		return find(p) == find(q);
	}
	//把q和q并在一起
	void unionElements( int p , int q ){
		int qID = find(q);
		int pID = find(p);
		if( pID == qID )
			return;

		for( int i = 0 ; i < count ; i ++ ){
			if( id[i] == qID )
				id[i] = pID;
		}
	}

	void println(){
		FOR(count)
			cout << id[i] << endl;
	}
};

 

2.采用指向父节点的思想实现

 

#include <iostream>
#include <ctime>
#include <cassert>

#define FOR(n) for( int i = 0 ; i < n ; i ++ )
using namespace std;

// 指向父节点的并查集
class UnionFind2{

private:
	int* parent;
	int count;

public:
	UnionFind2( int n ){
		parent = new int[n];
		this->count = n;
		FOR(n)
			parent[i] = i;		
	}
	~UnionFind2(){
		delete[] parent;
	}
	//找p节点的根
	int find( int p ){
		assert( p >= 0 && p < count );
		//当parent[p] = p的时候说明自己指向自己  即找到了"传进来"的p的根
		while( parent[p] != p )
			p = parent[p];
		return p;
	}
	bool isConnected( int p , int q ){
		//只需看是否在一个根下
		return find(p) == find(q);
	}
	void unionElements( int p , int q ){
		int Rootp = find(p);
		int Rootq = find(q);

		if( Rootp == Rootq )
			return;
		//这句话可以互换 即让Rootp的根指向根Rootq 这样他们就连在一起了
		parent[Rootp] = Rootq;
	}
	void println(){
		FOR(count)
			cout << i << " ";
		cout << endl;

		FOR(count)
			cout << parent[i] << " ";
		cout << endl;
	}
};

3.size优化

#include <iostream>
#include <ctime>
#include <cassert>

#define FOR(n) for( int i = 0 ; i < n ; i ++ )
using namespace std;

/************************************************************************/
/*									size优化                                                                     */
/************************************************************************/
class UnionFind3{

private:
	int* parent;
	int* sz;
	int count;

public:
	UnionFind3( int n ){
		parent = new int[n];
		sz = new int[n];
		this->count = n;
		FOR(n){
			parent[i] = i;
			sz[i] = 1;
		}	
	}
	~UnionFind3(){
		delete[] sz;
		delete[] parent;
	}
	//找p节点的根
	int find( int p ){
		assert( p >= 0 && p < count );
		//当parent[p] = p的时候说明自己指向自己  即找到了"传进来"的p的根
		while( parent[p] != p )
			p = parent[p];
		return p;
	}
	bool isConnected( int p , int q ){
		//只需看是否在一个根下
		return find(p) == find(q);
	}
	void unionElements( int p , int q ){
		int Rootp = find(p);
		int Rootq = find(q);

		if( Rootp == Rootq )
			return;
		//这句话可以互换 即让Rootp的根指向根Rootq 这样他们就连在一起了
		//parent[Rootp] = Rootq;
		if( sz[Rootp] < sz[Rootq] ){
			parent[Rootp] = Rootq;
			sz[Rootq] += sz[Rootp];
		}
		else{
			parent[Rootq] = Rootp;
			sz[Rootp] += sz[Rootq];
		}
	}
	void println(){
		FOR(count)
			cout << i << " ";
		cout << endl;

		/*	FOR(count)
		cout << parent[i] << " ";
		cout << endl;*/
		FOR(count){
			cout << i << "->" << parent[i] << endl;
		}
	}
};

4、路径压缩

#include <iostream>
#include <ctime>
#include <cassert>

#define FOR(n) for( int i = 0 ; i < n ; i ++ )
using namespace std;

// rank优化
/************************************************************************/
/*						路径压缩优化                                                                     */
/************************************************************************/
class UnionFind4{

private:
	int* parent;
	int* rank;
	int count;

public:
	UnionFind4( int n ){
		parent = new int[n];
		rank = new int[n];
		this->count = n;
		FOR(n){
			parent[i] = i;
			rank[i] = 1;
		}

	}
	~UnionFind4(){
		delete[] rank;
		delete[] parent;
	}
	//找p节点的根
	int find( int p ){
		assert( p >= 0 && p < count );
		//当parent[p] = p的时候说明自己指向自己  即找到了"传进来"的p的根
		//while( parent[p] != p ){
		//	parent[p] = parent[parent[p]];
		//	p = parent[p];
		//}
		//return p;
		if( p != parent[p] )
			parent[p] = find(parent[p]);
		
		return parent[p];
	}
	bool isConnected( int p , int q ){
		//只需看是否在一个根下
		return find(p) == find(q);
	}
	void unionElements( int p , int q ){
		int Rootp = find(p);
		int Rootq = find(q);

		if( Rootp == Rootq )
			return;
		//这句话可以互换 即让Rootp的根指向根Rootq 这样他们就连在一起了
		//parent[Rootp] = Rootq;
		if( rank[Rootp] < rank[Rootq] )
			parent[Rootp] = Rootq;
		
		else if( rank[Rootq] < rank[Rootp] )
			parent[Rootq] =  Rootp;
		//rank[Rootq] == rank[Rootp]
		else {
			parent[Rootp] = Rootq;
			rank[Rootq] += 1;
		}
			
		
	}
	void println(){
		FOR(count)
			cout << i << " ";
		cout << endl;

		FOR(count)
			cout << parent[i] << " ";
		cout << endl;
	}
};

主函数进行时间性能的测试

#include <iostream>
#include <ctime>
#include <cassert>
#include "UnionFind1.h"
#include "UnionFind2.h"
#include "UnionFind3.h"
#include "UnionFind4.h"
#define FOR(n) for( int i = 0 ; i < n ; i ++ )

using namespace std;



void test1( int n ){

	UnionFind uf(n);
	time_t start = clock();

	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 end = clock();
	cout << "Times:" << double(end-start)/CLOCKS_PER_SEC << "s" <<endl;

//	uf.println();
}
void test2( int n ){
	UnionFind2 uf2(n);
	time_t start = clock();

	for( int i = 0 ; i < n ; i ++ ){
		int a = rand()%n;
		int b = rand()%n;
		uf2.unionElements(a,b);
	}

	for( int i = 0 ; i < n ; i ++ ){
		int a = rand()%n;
		int b = rand()%n;
		uf2.isConnected(a,b);
	}
	time_t end = clock();
	cout << "Times:" << double(end-start)/CLOCKS_PER_SEC << "s" <<endl;

	uf2.println();
}
void test3( int n ){
	UnionFind3 uf3(n);
	time_t start = clock();

	for( int i = 0 ; i < n ; i ++ ){
		int a = rand()%n;
		int b = rand()%n;
		uf3.unionElements(a,b);
	}

	for( int i = 0 ; i < n ; i ++ ){
		int a = rand()%n;
		int b = rand()%n;
		uf3.isConnected(a,b);
	}
	time_t end = clock();
	cout << "Times:" << double(end-start)/CLOCKS_PER_SEC << "s" <<endl;

	uf3.println();
}
void test4( int n ){
	UnionFind4 uf4(n);
	time_t start = clock();

	for( int i = 0 ; i < n ; i ++ ){
		int a = rand()%n;
		int b = rand()%n;
		uf4.unionElements(a,b);
	}

	for( int i = 0 ; i < n ; i ++ ){
		int a = rand()%n;
		int b = rand()%n;
		uf4.isConnected(a,b);
	}
	time_t end = clock();
	cout << "Times:" << double(end-start)/CLOCKS_PER_SEC << "s" <<endl;

		uf4.println();
}
int main()
{
	//对每一种实现方式进行时间测试
	int n = 10;
//	test1(n);
	test2(n);
//	test3(n);
//	test4(n);
	
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值