并查集是一种维护集合的数据结构。它支持以下两个操作:
1.合并两个集合
2.判断两个元素是否在一个集合
初始化:一开始,每个元素都是一个独立的集合
查找:规定一个集合中只有一个根节点。查找操作就是反复寻找根节点,直至找到根节点。
合并:一般给出两个元素,要求把这两个元素所在集合合并。具体实现上先判断两个元素是否属于同一个集合,两个元素属于不同集合时才合并。(如给定元素A,B 合并操作Father[A]=B 或 Father[B]=A)
例题1
#include<bits/stdc++.h>
using namespace std;
#define N 100
int father[N];
bool isRoot[N] = {false};
// 寻找根节点
int findfather(int x)
{
int a = x;
while(father[x]!=x)
{
x = father[x];
}
// 路径压缩 优化 可不写
while(a!=father[a])
{
int z = a;
a = father[a];
father[z]=x;
}
return x;
}
// 若两个元素不在一个集合中 则将它们合并 否则不操作
void Union(int x,int y)
{
int FatherX = findfather(x);
int FatherY = findfather(y);
if(FatherX!=FatherY)
father[FatherX] = FatherY;
}
int main()
{
//数码宝贝个数n 好朋友的组数m
int n,m;
cin>>n>>m;
int a,b;
// 最开始每个元素都是一个独立的集合
for(int i=1;i<=n;++i)
{
father[i]=i;
}
// m组好友关系
for(int j=0;j<m;++j)
{
cin>>a>>b;
Union(a,b);
}
// 记录某节点是否为根节点
for(int i=1;i<=n;++i)
{
int f = findfather(i);
isRoot[f]=true;
}
// 统计集合数量
int count = 0;
for(int i=1;i<=n;++i)
{
if(isRoot[i])
count++;
}
cout<<count<<endl;
return 0;
} 例题2 计算岛屿数量
思路:可DFS、BFS、并查集
//定义并查集类及其操作
class UnionFind{
private:
// count计数最终的连通块数目
int count;
vector<int>father;
public:
UnionFind(vector<vector<char>>& v)
{
count = 0;
father.clear();
int row = v.size();
int column = v[0].size();
for(int i=0;i<row;++i)
{
for(int j=0;j<column;++j)
{
if(v[i][j]=='1')
{
//初始化每个符合要求的结点的父结点为其自身
father.push_back(i*column+j);
++count;
}
else father.push_back(-1);
}
}
}
int find(int x)
{
while(father[x]!=x)
{
x = father[x];
}
return x;
}
void Union(int x,int y)
{
int father_x = find(x);
int father_y = find(y);
if(father_x!=father_y)
{
father[father_x]=father_y;
--count;
}
}
int getCount()
{
return count;
}
};
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
if(grid.empty()) return 0;
UnionFind uf(grid);
int r = grid.size();
int c = grid[0].size();
for(int i=0;i<r;++i)
{
for(int j=0;j<c;++j)
{
if(grid[i][j]=='1')
{
int cur = i*c+j;
// 访问过即置0
grid[i][j] = '0';
//if(i-1>=0 && grid[i-1][j]=='1')
// uf.Union(cur,(i-1)*c+j);
//if(j-1>=0 && grid[i][j-1]=='1')
// uf.Union(cur,i*c+j-1);
// 向右向下搜索即可 左上已经搜索过
// 注意这里的写法是连着的if
if(i+1<r && grid[i+1][j]=='1')
uf.Union(cur,(i+1)*c+j);
if(j+1<c && grid[i][j+1]=='1')
uf.Union(cur,i*c+j+1);
}
}
}
return uf.getCount();
}
};
京公网安备 11010502036488号