并查集效率测试

pre全文基础设定-----------------------------n 集合总数(即并查集个体数)m 总共操作数f find操作数Ackerman(k,n) = {n+1/k==0 | Ackerman.iter(n+1,k=k-1)(k-1,n)} / 具体定义可以看wikialpha(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)
时间: 2024-10-20 03:57:20

并查集效率测试的相关文章

并查集(Union Find):实现及其优化(c++)

1.什么是并查集 并查集是用来管理元素分组的数据结构.可以高效进行如下操作: 查询元素a.b十是否在同一组 合并a.b所在的组 并查集可以进行合并操作但不能进行分割操作. 2.并查集的结构 并查集采用多叉树形结构实现,每个元素对应一个结点,每个组对应一棵树.重点关注结整体形成一个树形结构,而不是树的形状等信息. 3.并查集的实现 3.1 初始化 对于并查集,一般采用数组来实现,其中元素为数组的索引,其父辈为数组索引对应内容. 在初始化中,将每个元素父辈设为自己,即自己形成一组,并对用一个rank

测试赛A - Colored Sticks(并查集+字典树+欧拉回路)

A - Colored Sticks Time Limit:5000MS     Memory Limit:128000KB     64bit IO Format:%I64d & %I64u Submit Status Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sti

测试赛F - Dragon Balls(并查集)

F - Dragon Balls Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description Five hundred years later, the number of dragon balls will increase unexpectedly, so it's too difficult for Monkey King(WuKong) to

【NOIP模拟_54测试】【并查集】【二进制】【搜索】【区间序列类】

第一题 Mushroom的序列 大意: 给一个序列,求一段连续最长区间满足:最多改变一个数,使得区间是严格的上升子序列. 解: 直接扫描一遍,记一个最长上升子序列编号.然后从每一个编号为1 的点来判断是否可以将两个序列合并,有两种情况,讨论需要注意多种子情况...我可能想的比较复杂,所以第一遍写的时候少考虑了一些相等的情况,就WA 了一个点. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #i

[CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)

题目描述 比特山是比特镇的飙车圣地.在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构. 因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字$l_i,r_i$量化地表示一条车道的承受区间,只有当汽车以不小于$l_i$且不大于$r_i$的速度经过这条车道时,才不会对路面造成伤害. $Byteasar$最近新买了一辆跑车,他想在比特山飙一次车.$Byteasar$计划选择两个不同的点$S,T$,然后在它

log2取整效率测试

RMQ问题中有个ST算法,当然还有个标准算法.LCA问题可以转化为带限制的RMQ(RMQ+-1)问题来解决.我们姑且认为这些问题的时间复杂度是查询$O(1)$的.但是,注意到对于RMQ(/+-1)问题,这个问题有个长度的限制,我们记为n.那么对于每个查询,我们都要询问一个范围[L,R],1<=L<=R<=n.这个区间的长度为R-L+1.然后我们将原区间分成两个Sparse Table上的项,即长度为int_log2(R-L+1)-1的两个子区间求解min,即合并两个子区间的信息. 那么问

并查集详解 (转)

http://blog.csdn.net/dellaserss/article/details/7724401 我从CSDN转的文章,原文作者我也不懂是谁,文章写得真的是诙谐幽默,使得内容更容易理解了. 来看一个实例,杭电OJ 1232畅通工程 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可).问最少还需要建

hdu1232&amp;&amp; hdu1213(简单并查集)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232 畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 35673    Accepted Submission(s): 18897 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每

poj 2236:Wireless Network(并查集,提高题)

Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 16065   Accepted: 6778 Description An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computer