文章目录
9.6小节——数据结构专题(2)->并查集
文章有待进一步完善。。。。。
9.6.1-并查集的定义
数据结构并查集分别取自Union(合并)、Find(查找)、Set(集合),支持合并与查找操作。
9.6.2-并查集的基本操作
并查集的使用需要初始化father数组,再根据需要进行查找或合并操作。
1.初始化
2.查找
3.合并
并查集的基本操作
//并查集的基本操作
//初始化,每一个元素都是独立的一个集合
for(int i = 1;i <= N;i++){
father[i] = i;
}
//查找,对给定的结点寻找其根结点
//递推代码findFather函数返回元素x所在集合的根结点
int findFather(int x){
while(x != father[x]){//如果不是根结点,继续循环
x = father[x];
}
return x;
}
//合并
void Union(int a,int b){
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB){
father[faA] = faB;//合并
}
}
9.6.3-路径压缩
//路径压缩对查找进行优化,把子结点的父结点都指向根结点
int findFather(int x){
int a = x;
while(x != father[x]){//寻找根结点
x = father[x];
}
while(a != father[a]){//把所有结点的father都改成根结点
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
//递归写法
int findFather(int v){
if(v == father[v]) return v;
else{
int F = findFather(father[v]);
father[v] = F;
return F;
}
}
例题-好朋友
//例题-好朋友
#include <cstdio>
const int N = 110;
int father[N];
bool isRoot[N];
int findFather(int x){
int a = x;
while(x != father[x]){
x = father[x];
}
//路径压缩
while(a != father[a]){
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
void Union(int a,int b){//合并a和b所在的集合
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB){
father[faA] = faB;
}
}
void init(int n){//初始化father[i]为i,且flag[i]为false
for(int i = 1;i <= n;i++){
father[i] = i;
isRoot[i] = false;
}
}
int main(){
int n,m,a,b;
scanf("%d%d",&n,&m);
init(n);
for(int i = 0;i < m;i++){
scanf("%d%d",&a,&b);
Union(a,b);
}
for(int i = 1;i <= n;i++){
isRoot[findFather(i)] = true;
}
int ans = 0;
for(int i = 1;i <= n;i++){
ans += isRoot[i];
}
printf("%d\n",ans);
return 0;
}
Codeup习题
链接: http://codeup.cn/contest.php?cid=100000615
问题 A:通信系统
链接: http://codeup.cn/problem.php?cid=100000615&pid=0
//问题 A:通信系统
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1010;
int father[N];
bool isRoot[N];
int findFather(int v){
if(v == father[v]) return v;
else{
int F = findFather(father[v]);
// F=father[v];
father[v] = F;//两种方法都对
return F;
}
}
void init(int n){
for(int i=1;i<=n;i++){
father[i] = i;
isRoot[i] = false;
}
}
void Union(int a,int b){//合并a和b所在的集合
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB){
father[faB] = faA;//此处注意father[faA] = faB(??);不对
// father[faA] = faB;
}
}
int main(){
int n,m,a,b;
while(cin>>n>>m){
if(n==0 && m==0) break;
init(n);
for(int i = 0;i < m;i++){//输入数据,构建并查集
cin>>a>>b;
Union(a,b);
}
if(m > n-1){
cout<<"No"<<endl;
continue;
}
int i;
for(i = 1; i < n;i++){//遍历并查集检测其是否只有一个共同的根
if(father[i] != father[i+1])
break;
}
if(i == n){
cout<<"Yes"<<endl;
}
else{
cout<<"No"<<endl;
}
}
return 0;
}
问题 B:
链接: http://codeup.cn/problem.php?cid=100000615&pid=1
问题C:
链接: http://codeup.cn/problem.php?cid=100000615&pid=2
问题D:
链接: http://codeup.cn/problem.php?cid=100000615&pid=3
平衡二叉树小结
平衡二叉树(AVL)是所有结点满足左右子树高度之差(即平衡因子)绝对值小于1的二叉查找树(BST),特别注意插入与删除后对不平衡树的调整RR、LL、RL、LR。