【问题标题】:Connected component labeling with diagonal connections using union-find使用 union-find 对角连接的连接组件标签
【发布时间】:2017-11-12 01:38:13
【问题描述】:

我正在尝试开发一个连接组件算法的修改,作为这个问题的答案:Connected Component Labelling

基本上,我有由 0 和 1 组成的 2d 和 3d 矩阵。我的问题是找到 1 的连接区域,分别标记每个区域。矩阵大小可能非常大(由 2-d 中的 5e4×5e4 元素和 3d 中的 1000^3 个元素组成)。所以我需要一些不会给堆栈内存带来压力的东西,而且它的速度足够快,可以在模拟过程中重复几次。

使用深度优先搜索对该问题的最受好评的答案给出了堆栈溢出错误(如评论中所述)。我一直在尝试使用另一个用户建议的联合查找算法。

原始代码(由用户 Dukeling 编写)非常适用于大型二维矩阵,但我希望元素之间有对角线连接。这是我的代码,以及我尝试使用的示例输入:

#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 个命令来实现元素之间的对角连接。这是对联合查找算法的有效修改吗?我特别搜索了谷歌和stackoverflow,但我找不到任何对角连接的例子。此外,我想将其扩展到 3 个维度 - 所以我需要添加 26 个命令进行检查。这种方式会很好地扩展吗?我的意思是代码似乎适用于我的情况,但有时我会随机得到一个未标记的孤立元素。我不想将它与我的代码集成,只是为了在几个月后发现一个错误。

谢谢。

【问题讨论】:

  • 您可以重写一个函数以将数组用作堆栈而不是递归,然后您不会用完数组,直到内存不足。如果你有 goto 可用,而不是调用函数,推送一些返回地址的标记,将其参数推送到堆栈上,然后转到它的开始。一开始,从堆栈中弹出参数并继续。要返回,请弹出返回地址并前往那里。如果您没有 goto,请将函数转换为 while 循环。虽然堆栈上有任何事情要做,但尽你所能,将递归调用转换为将 todo 对象推送到堆栈。
  • 嗨,我确实是用数组做的。因此,在 2d 中,函数递归调用元素的四个邻居。它很快就耗尽了内存。我还将堆栈大小调整为最大允许限制。

标签: algorithm matrix connected-components


【解决方案1】:

您使用联合查找算法的方法没有任何问题。联合查找在任何图上运行。对于它检查的每个节点,它都会检查其连接的节点以确定它们是否在同一个子集中。您的方法似乎就是这样做的,检查任何观察到的节点的 8 个相邻节点。联合查找算法与图形的尺寸无关。只要您的图形正确对应于该维度,您就可以将该方法扩展到 3d 或任何维度。如果您遇到此错误,您可以发布该错误的示例,或查看代码审查:https://codereview.stackexchange.com/

【讨论】:

  • 您好,感谢您的回复。所以我什至发布这个问题的原因是因为我无法让它在 3d 中工作。我想知道我是否有一些概念上的困难。如果您认为这没问题,我想我会编辑原始问题以包含 3d 代码。
  • 如果您将其作为单独的问题重新发布,您可能会受到更多关注。
  • 另外,根据你的新问题的性质,考虑它是属于这里还是属于代码审查
  • 是的,我认为你是对的..我应该用非工作代码问一个新问题。
  • 好主意。此外,如果您认为这个答案对您解决这个问题有足够的帮助,您可能希望接受它,以免将注意力从新的未回答问题上转移。
猜你喜欢
  • 2017-05-07
  • 2015-04-08
  • 2011-09-29
  • 2013-01-06
  • 2018-03-08
  • 2011-01-10
  • 2014-05-19
  • 2011-07-31
相关资源
最近更新 更多