并查集
leetcode第200题。
看到有人写的不错:https://leetcode-cn.com/problems/number-of-islands/solution/cyu-yan-bing-cha-ji-mo-ban-jian-yi-bei-xia-lai-by-/
收录下来。
// LeetCode200. 岛屿数量
// 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
// 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
// 此外,你可以假设该网格的四条边均被水包围。
// 提示:
// m == grid.length
// n == grid[i].length
// 1 <= m, n <= 300
// grid[i][j] 的值为 '0' 或 '1'
// 算法:并查集
// 重点:
// 1.UFInit()如何初始化,将实际问题映射为并查集
// 2.何时使用Union()将节点分类
// 3.如何使用Union()将节点分类
/* 并查集模板:权重平衡+路径压缩 */
int g_count;
int* g_parent;
int* g_size; /* 权重:这棵树有多少个节点 */
/* 并查集的初始化 */
void UFInit(int n)
{
g_count = n;
g_parent = (int*)calloc(n, sizeof(int));
if (g_parent == NULL) {
printf("g_parent calloc fail\n");
return;
}
g_size = (int*)calloc(n, sizeof(int));
if (g_size == NULL) {
printf("g_size calloc fail\n");
return;
}
int i;
for (i = 0; i < n; i++) {
g_parent[i]= i; /* 父节点初始化为自己 */
g_size[i] = 1; /* 权重初始化为1 */
}
}
/* 查找x的根节点 */
int Find(int x)
{
while (x != g_parent[x]) {
g_parent[x] = g_parent[g_parent[x]]; /* 路径压缩 */
x = g_parent[x];
}
return x;
}
/* 将p和q连通 */
void Union(int p, int q)
{
int rootP = Find(p);
int rootQ = Find(q);
if (rootP == rootQ) {
return;
}
/* 根据权重,把小树挂在大树下面,然后连通分量减一 */
if (g_size[rootP] < g_size[rootQ]) {
g_parent[rootP] = rootQ;
g_size[rootQ] += g_size[rootP];
} else {
g_parent[rootQ] = rootP;
g_size[rootP] += g_size[rootQ];
}
g_count--;
}
/* 判断p和q是否连通 */
bool IsConnected(int p, int q)
{
int rootP = Find(p);
int rootQ = Find(q);
return rootP == rootQ;
}
/* 返回当前的连通分量数目 */
int GetCount()
{
return g_count;
}
// 算法:
// 1.虚构哑巴节点 dummy,把所有的0与之连通
// 2.把相邻的1连通
// 3.遍历结束后,获得当前连通分量,减去1个(0的连通),剩下的就是岛屿数量
int numIslands(char** grid, int gridSize, int* gridColSize)
{
if (grid == NULL || gridSize < 1 || gridColSize == NULL) {
return 0;
}
int m = gridSize;
int n = gridColSize[0];
int dummy = m * n;
int ans;
UFInit(m * n + 1);
/* 方向数组 */
int dir[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
int i;
int j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
if (grid[i][j] == '0') {
Union(i * n + j, dummy);
continue;
}
int k;
for (k = 0; k < 4; k++) {
int nx = i + dir[k][0];
int ny = j + dir[k][1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == '1') {
Union(nx * n + ny, i * n + j);
}
}
}
}
ans = GetCount() - 1;
/* 最后记得释放内存 */
free(g_parent);
g_parent = NULL;
free(g_size);
g_size = NULL;
return ans;
}
作者:little_bee
链接:https://leetcode-cn.com/problems/number-of-islands/solution/cyu-yan-bing-cha-ji-mo-ban-jian-yi-bei-xia-lai-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
还有个C with class的
#define ERROR -1
typedef struct{
int n;
int familyCnt;
int* father;
int* size;
}UnionFind;
UnionFind* unionFindCreate(int n){
UnionFind* obj = (UnionFind*)malloc(sizeof(UnionFind));
if (obj == NULL){
return NULL;
}
obj->n = n;
obj->familyCnt = n;
obj->father = (int*)malloc(n * sizeof(int));
obj->size = (int*)malloc(n * sizeof(int));
if (obj->father == NULL || obj->size == NULL){
free(obj->father);
free(obj->size);
free(obj);
return NULL;
}
for (int i = 0; i < n; ++i){
obj->father[i] = i;
obj->size[i] = 1;
}
return obj;
}
int getFamilyCnt(UnionFind* obj){
if (obj == NULL){
return ERROR;
}
return obj->familyCnt;
}
int getFather(UnionFind* obj, int index){
if (obj == NULL || index < 0 || index >= obj->n){
return ERROR;
}
if (obj->father[index] == index){
return index;
}
obj->father[index] = getFather(obj, obj->father[index]);
return obj->father[index];
}
int connect(UnionFind* obj, int src, int dst){
if (obj == NULL || src < 0 || src >= obj->n || dst < 0 || dst >= obj->n){
return ERROR;
}
int src_father = getFather(obj, src);
int dst_father = getFather(obj, dst);
if (src_father == dst_father){
return 0;
}
else{
int src_size = obj->size[src_father];
int dst_size = obj->size[dst_father];
if (src_size > dst_size){
obj->size[src_father] += obj->size[dst_father];
obj->size[dst_father] = 0;
(obj->father)[dst_father] = src_father;
--obj->familyCnt;
}
else{
obj->size[dst_father] += obj->size[src_father];
obj->size[src_father] = 0;
(obj->father)[src_father] = dst_father;
--obj->familyCnt;
}
return 1;
}
}
int getSize(UnionFind* obj, int index){
if (obj == NULL || index < 0 || index >= obj->n){
return ERROR;
}
return obj->size[getFather(obj, index)];
}
void unionFindFree(UnionFind* obj){
if (obj != NULL){
free(obj->father);
free(obj->size);
free(obj);
}
}