并查集效率测试

pre
全文基础设定
-----------------------------
n 集合总数(即并查集个体数)
m 总共操作数
f find操作数
Ackerman(k,n) = {n+1/k==0 | Ackerman.iter(n+1,k=k-1)(k-1,n)} / 具体定义可以看wiki
alpha(n) = min{k:Ackerman(k,1)>=n}

引自《算法导论》

并查集(disjoint set)有两种优化: 按秩合并(union by rank,UR) 和 路径压缩(path compression,PC)

其中,
仅用按秩合并的时间复杂度$\text{O} ( m \log n)$
仅用路径压缩的时间复杂度$\Theta ( n + f \cdot ( 1 + \log_{2 + f / n} n))$
两个都用的时间复杂度$\text{O} ( m \alpha ( n))$

测试程序

并查集程序

#define sizex 100000000
int f[sizex],rk[sizex];
struct ds{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1;
	}
	void find(int t){
		return ~f[t]?t:find(f[t]);
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		f[b]=a;
	}
} djs;
struct dsU{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1,rk[i]=1;
	}
	void find(int t){
		return ~f[t]?t:find(f[t]);
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		if(rk[a]>=rk[b]){
			f[b]=a;
			rk[a]+=rk[b];
		}else{
			f[a]=b;
			rk[b]+=rk[a];
		}
	}
} djsU;
struct dsP{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1;
	}
	void find(int t){
		return ~f[t]?t:f[t]=find(f[t]);
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		f[b]=a;
	}
} djsP;
struct dsUP{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1,rk[i]=1;
	}
	void find(int t){
		return ~f[t]?t:f[t]=find(f[t]);
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		if(rk[a]>=rk[b]){
			f[b]=a;
			rk[a]+=rk[b];
		}else{
			f[a]=b;
			rk[b]+=rk[a];
		}
	}
} djsUP;

测试程序

#define sizex 100000000
int f[sizex],rk[sizex];
struct ds{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1;
	}
	int find(int t){
		return ~f[t]?find(f[t]):t;
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		f[b]=a;
	}
} djs;
struct dsU{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1,rk[i]=1;
	}
	int find(int t){
		return ~f[t]?find(f[t]):t;
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		if(rk[a]>=rk[b]){
			f[b]=a;
			rk[a]+=rk[b];
		}else{
			f[a]=b;
			rk[b]+=rk[a];
		}
	}
} djsU;
struct dsP{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1;
	}
	int find(int t){
		return ~f[t]?f[t]=find(f[t]):t;
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		f[b]=a;
	}
} djsP;
struct dsUP{
	inline void init(int size){
		for(int i=0;i<size;++i) f[i]=-1,rk[i]=1;
	}
	int find(int t){
		return ~f[t]?f[t]=find(f[t]):t;
	}
	inline void join(int a,int b){
		a=find(a),b=find(b);
		if(a==b) return;
		if(rk[a]>=rk[b]){
			f[b]=a;
			rk[a]+=rk[b];
		}else{
			f[a]=b;
			rk[b]+=rk[a];
		}
	}
} djsUP;
#include <cstdio>
#include <random>
#include <malloc.h>
#include <sys/time.h>
using namespace std;
struct cmd{
	bool type;
	int a,b;
}temp;
cmd* data;
long long mytic(){
	long long result = 0.0;
	struct timeval tv;
	gettimeofday( &tv, NULL );
	result = ((long long)tv.tv_sec)*1000000 + (long long)tv.tv_usec;
	return result;
}
#define dic1() disA(generator)
#define dic2() disB(generator)
void genData(int a,int b,int c){
	mt19937 generator;
	uniform_int_distribution<int> disA(0,a-1);
	uniform_int_distribution<int> disB(0,b+c-1);
	int k=b+c,i=0,j;
	for(;i<b;++i) data[i].type=0,data[i].a=dic1(),data[i].b=dic1();
	for(;i<k;++i) data[i].type=1,data[i].a=dic1();
	for(i=0;i<k;++i){
		j=dic2();
		if(i==j) continue;
		temp=data[i];
		data[i]=data[j];
		data[j]=temp;
	}
}
void testN(int a,int b,int c){
	int k=b+c,i;
	printf("none opt\n");
	long long start=mytic();
	djs.init(a);
	for(i=0;i<k;++i){
		switch(data[i].type){
			case 0:
			djs.join(data[i].a,data[i].b);
			case 1:
			djs.find(data[i].a);
		}
	}
	start=mytic()-start;
	printf("Time usage: %lld us\n",start);
}
void testU(int a,int b,int c){
	int k=b+c,i;
	printf("union by rank opt\n");
	long long start=mytic();
	djsU.init(a);
	for(i=0;i<k;++i){
		switch(data[i].type){
			case 0:
			djsU.join(data[i].a,data[i].b);
			case 1:
			djsU.find(data[i].a);
		}
	}
	start=mytic()-start;
	printf("Time usage: %lld us\n",start);
}
void testP(int a,int b,int c){
	int k=b+c,i;
	printf("path compression opt\n");
	long long start=mytic();
	djsP.init(a);
	for(i=0;i<k;++i){
		switch(data[i].type){
			case 0:
			djsP.join(data[i].a,data[i].b);
			case 1:
			djsP.find(data[i].a);
		}
	}
	start=mytic()-start;
	printf("Time usage: %lld us\n",start);
}
void testUP(int a,int b,int c){
	int k=b+c,i;
	printf("both opt\n");
	long long start=mytic();
	djsUP.init(a);
	for(i=0;i<k;++i){
		switch(data[i].type){
			case 0:
			djsUP.join(data[i].a,data[i].b);
			case 1:
			djsUP.find(data[i].a);
		}
	}
	start=mytic()-start;
	printf("Time usage: %lld us\n",start);
}
int main(){
	int a,b,c,i,j,k,l,m,n,N,U,P,UP;
	data=(cmd*)malloc(200000000*sizeof(cmd));
	while(printf("0 to quit> "),scanf("%d",&a),a){
		printf("N U P UP\n");
		scanf("%d%d%d%d",&N,&U,&P,&UP);
		printf("set size: ");
		scanf("%d",&a);
		printf("op join num: ");
		scanf("%d",&b);
		printf("op find num: ");
		scanf("%d",&c);
		if(a>100000000||(b+c)>200000000) continue;
		i=b+c;
		printf("total %d ops\n", b+c);
		genData(a,b,c);
		if(N) testN(a,b,c);
		if(U) testU(a,b,c);
		if(P) testP(a,b,c);
		if(UP) testUP(a,b,c);
	}
	free(data);
	return 0;
}

raw data

set size: 500	join operations: 500	find operations: 500
total 1000 ops
none opt Time usage: 383 us
Union by Rank opt Time usage: 44 us
Path Compression opt Time usage: 48 us
both opt(s) Time usage: 39 us
set size: 10000	join operations: 7000	find operations: 10000
total 17000 ops
none opt Time usage: 1159 us
Union by Rank opt Time usage: 246 us
Path Compression opt Time usage: 274 us
both opt(s) Time usage: 245 us
set size: 100000	join operations: 70000	find operations: 100000
total 170000 ops
none opt Time usage: 134035 us
Union by Rank opt Time usage: 3096 us
Path Compression opt Time usage: 3291 us
both opt(s) Time usage: 2967 us
set size: 400000	join operations: 280000	find operations: 400000
total 680000 ops
none opt Time usage: 5293524 us
Union by Rank opt Time usage: 14099 us
Path Compression opt Time usage: 14466 us
both opt(s) Time usage: 12509 us
set size: 1000000	join operations: 700000	find operations: 1000000
total 1700000 ops
Union by Rank opt Time usage: 48863 us
Path Compression opt Time usage: 40933 us
both opt(s) Time usage: 41501 us
set size: 10000000	join operations: 7000000	find operations: 10000000
total 17000000 ops
Union by Rank opt Time usage: 882355 us
Path Compression opt Time usage: 1118981 us
both opt(s) Time usage: 814115 us
set size: 100000000	join operations: 70000000	find operations: 100000000
total 170000000 ops
Union by Rank opt Time usage: 13025344 us
Path Compression opt Time usage: 19499277 us
both opt(s) Time usage: 12493686 us
(-O2)
=================================================== set size: 100000000 join operations: 60000000 find operations: 120000000 total 180000000 ops Union by Rank opt Time usage: 10360505 us Path Compression opt Time usage: 11255217 us both opt(s) Time usage: 9452136 us
(-O3) ===================================================== bug fixed: add `break' set size: 100000000 join operations: 60000000 find operations: 120000000 total 180000000 ops Union by Rank opt Time usage: 12039494 us Path Compression opt Time usage: 13178722 us both opt(s) Time usage: 13395750 us set size: 100000000 join operations: 50000000 find operations: 140000000 total 190000000 ops Union by Rank opt Time usage: 11454054 us Path Compression opt Time usage: 10056804 us both opt(s) Time usage: 11322394 us set size: 100000000 join operations: 100000000 find operations: 100000000 total 200000000 ops Union by Rank opt Time usage: 20773924 us Path Compression opt Time usage: 46671332 us both opt(s) Time usage: 19270817 us (-O3)
posted @ 2015-03-29 00:51  zball  阅读(261)  评论(2编辑  收藏  举报