并查集总结
今天总结一下并查集,这个完了之后,寒假学的数据结构基础的模板类的题目差不多就完了,对于模板题,敲上10遍、20遍、30遍,那么模板就不是模板,就成为了你自己的东西,就好像 A+B 一辈子也忘不了,以后每天敲一遍模板题,加深对模板的理解。
并查集,一般使用的是 数组实现、树实现,其中数组实现时间复杂度较高,树实现也就是分离集合森林 查找、合并的时间复杂度不会
超过 O(log2n)
n个人,m对有亲戚关系的
10 7
1 2
2 3
2 4
3 4
5 6
6 7
8 9
初始化:{1} {2} {3} {4} {5} {6} {7} {8} {9} {10}
初步合并 {1,2} {2,3} {2,4} {3,4} {5,6} {6,7} {8,9} {10}
最终合并 {1,2,3,4} {5,6,7} {8,9} {10}
分离集合森林如下:
一、树实现
并查集中,每一个集合代表一个分离集合树,多个集合形成一个森林,树根当做集合的代表,每一个节点都有一个父指针来表示附属关系,根节点指向自身,在一个树高度很低的树种查找一个节点所用的时间很少。所以 并查集的分离集合树的 开辟一个秩的int 数据来保证构造的分离集合树的高度较低,在合并的时候,让较小的秩的根指向较大秩的根,若俩个秩相等,任意一个指向另一个,并且它的秩+1;
POJ 2524
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> const int N= 50001; using namespace std; struct node{ int data; // 节点数据域 int zhi; //秩 存放子树高度 int parent;//父节点 }t[N]; int n,m; int Find(int r)//查 { while(t[r].parent!=r)//判断双亲是不是自己 { r = t[r].parent; //循环查找X, } /* if(t[r].parent==r) //递归实现 return r; else return (Find(t[r].parent)); */ int i=r,j;//压缩路径 while (t[i].parent!=r)//i的父亲不是r,进行压缩 { j=t[i].parent;//记录i的父亲 t[i].parent=r;//改变i的父亲 i=j;//判断i的父亲 } return r; } void Merge(int x,int y)//并:合并x y的子树 { x = Find(x); //找x所在子树的编号 y = Find(y); if(t[x].zhi>t[y].zhi) //较小秩 指向 较大秩 { t[y].parent = x; //y链接到x上,x为父节点 } else { t[x].parent = y; if(t[x].zhi == t[y].zhi) //x连接y,y做为父节点 t[y].zhi++; //y的子树高度+1 } } void init() { for(int i = 1;i<=n;i++) { t[i].data = i; t[i].zhi = 0;//初始化 树高度为0 t[i].parent = i;//父节点是自己 } } int main() { int x,y,l=0; while(scanf("%d%d",&n,&m)) { if(n==0 && m==0) break; l++; init(); for(int i = 0;i<m;i++) { scanf("%d%d",&x,&y); Merge(x,y); } int sum = 0; for(int i = 1;i<=n;i++) { if(t[i].parent!=i) sum++; } printf("Case %d: %d\n",l,n-sum); } return 0; }
数组实现
#include <stdio.h> int bin[100010]; int findx(int x) { int r=x; while(bin[r] !=r) r=bin[r]; return r; } void merge(int x,int y) { int fx,fy; fx = findx(x); fy = findx(y); if(fx != fy) bin[fx]=fy; } int main() { int n,m,i,x,y,count; int t=1; while(~scanf("%d%d",&n,&m)) { if(n==0 && m == 0) break; for(i=1;i<=n;i++) { bin[i] = i; } for(i=1;i<=m;i++) { scanf("%d %d",&x,&y); merge(x,y); } for(count = 0, i=1;i<=n;i++) if(bin[i] == i) count ++; printf("Case %d: %d\n",t++,count); } return 0; }
时间: 2024-10-24 15:57:19