我正在尝试开发对连接组件算法的修改,我发现这是对这个问题的回答:Connected Component Labelling。
基本上,我有2d-和3d-矩阵,由0和1组成。我的问题是找到1s的连通区域,分别标记每个区域。矩阵大小可以非常大(由2-d中的5e4乘5e4元素和3d中的1000 ^ 3元素组成)。所以我需要一些不会对堆栈内存造成压力的东西,并且它足够快,可以在模拟过程中重复几次。
使用深度优先搜索,对该问题的最热烈回答会产生堆栈溢出错误(如注释中所述)。我一直在尝试使用另一个用户建议的union-find算法。
原始代码(由用户Dukeling提供)适用于大型2-d矩阵,但我想在元素之间建立对角连接。这是我的代码,我正在尝试使用示例输入:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
const int w = 8, h = 8;
int input[w][h] = {{1,0,0,0,1,0,0,1},
{1,1,0,1,1,1,1,0},
{0,1,0,0,0,0,0,1},
{1,1,1,1,0,1,0,1},
{0,0,0,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,1,0,0,1,1,1,0},
{1,0,1,1,0,1,0,1}};
int component[w*h];
void doUnion(int a, int b)
{
// get the root component of a and b, and set the one's parent to the other
while (component[a] != a)
a = component[a];
while (component[b] != b)
b = component[b];
component[b] = a;
}
void unionCoords(int x, int y, int x2, int y2)
{
if (y2 < h && x2 < w && input[x][y] && input[x2][y2] && y2 > 0 && x2 > 0)
doUnion(x*h + y, x2*h + y2);
}
int main()
{
int i, j;
for (i = 0; i < w*h; i++)
component[i] = i;
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++)
{
unionCoords(x, y, x+1, y);
unionCoords(x, y, x, y+1);
unionCoords(x, y, x+1, y+1);
unionCoords(x, y, x-1, y+1);
unionCoords(x, y, x+1, y-1);
unionCoords(x, y, x-1, y-1);
}
// print the array
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
if (input[x][y] == 0)
{
printf("%4d ",input[x][y]);
continue;
}
int c = x*h + y;
while (component[c] != c) c = component[c];
printf("%4d ", component[c]);
}
printf("\n");
}
}
如您所见,我添加了4个用于在元素之间进行对角连接的命令。这是union-find算法的有效修改吗?我特别搜索了谷歌和stackoverflow,但我找不到任何对角线连接的例子。另外,我想将它扩展到3个维度 - 所以我需要添加26个命令进行检查。这种方式会很好地扩展吗?我的意思是代码似乎适用于我的情况,但有时我随机得到一个未标记的孤立元素。我不想将它与我的代码集成,只是为了在几个月后发现一个错误。
感谢。
答案 0 :(得分:0)
使用union find算法的方法没有任何问题。联盟查找在任何图表上运行。对于它检查的每个节点,它检查其连接的节点以确定它们是否在同一子集中。您的方法似乎就是这样做,检查任何观察节点的8个相邻节点。联合查找算法与图形的尺寸无关。只要图表与该维度正确对应,您就可以将该方法扩展到3d或任何维度。如果您遇到此错误,可以发布该错误的示例,或查看代码审核:https://codereview.stackexchange.com/。