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)
其中,
仅用按秩合并的时间复杂度$ ext{O} ( m log n)$
仅用路径压缩的时间复杂度$Theta ( n + f cdot ( 1 + log_{2 + f / n} n))$
两个都用的时间复杂度$ ext{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
");
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
",start);
}
void testU(int a,int b,int c){
int k=b+c,i;
printf("union by rank opt
");
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
",start);
}
void testP(int a,int b,int c){
int k=b+c,i;
printf("path compression opt
");
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
",start);
}
void testUP(int a,int b,int c){
int k=b+c,i;
printf("both opt
");
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
",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
");
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
", 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)