二维阵列相邻算法

时间:2013-01-15 21:15:14

标签: arrays algorithm multidimensional-array

我有一个像这样的2D数组:

0,1,0,0,1
1,0,1,0,1
0,1,1,0,1
0,1,0,1,1
1,1,0,0,1

如果我们提取所有1的坐标,我们得到:

(height,width)
1,2
1,5
2,1
... 

所以现在我想找到由邻近1(非对角线)创建的区域。 为了做到这一点,我需要找到一种方法来检查邻居的邻居。我一直在考虑使用两个数组并将一个邻居的邻居交换为另一个邻居但是它不是一种非常有效的方式当谈到处理一个大阵列时。这个问题有更好的解决方案吗?

由于

2 个答案:

答案 0 :(得分:4)

有许多这样的方法,它们被称为连接组件标记。以下是一些不太旧的(没有特别的顺序):

  1. Light Speed Labeling For RISC Architectures,2009
  2. Optimizing Two-pass Connected-Component Labeling Algorithms,2009
  3. A Linear-time Component-Labeling Algorithm Using Contour Tracing Technique,2004
  4. 第二种方法在文献中被称为“吴的算法”(它们实际上是指较旧的论文,但其中提出的算法是相同的),并且被认为是这项任务中最快的算法之一。使用泛洪填充肯定是您想要使用的最后一种方法之一,因为与其中任何一种方法相比它都非常慢。该Wu算法是基于具有路径压缩的并集查找数据结构的两遍标记,并且相对容易实现。由于本文涉及8连接,我将包括用于处理4连接的示例代码(您的问题与此相关)。

    union-find结构的代码是从文章中获取的,但是你会在每个关于这个数据结构的文本中找到类似的代码。

    def set_root(e, index, root):
        # Set all nodes to point to a new root.
        while e[index] < index:
            e[index], index = root, e[index]
        e[index] = root
    
    def find_root(e, index):
        # Find the root of the tree from node index.
        root = index
        while e[root] < root:
            root = e[root]
        return root
    
    def union(e, i, j):
        # Combine two trees containing node i and j.
        # Return the root of the union.
        root = find_root(e, i)
        if i != j:
            root_j = find_root(e, j)
            if root > root_j:
                root = root_j
            set_root(e, j, root)
        set_root(e, i, root)
        return root
    
    def flatten_label(e):
        # Flatten the Union-Find tree and relabel the components.
        label = 1
        for i in xrange(1, len(e)):
            if e[i] < i:
                e[i] = e[e[i]]
            else:
                e[i] = label
                label += 1
    

    为简单起见,我假设数组在顶部和左侧用零填充。

    def scan(a, width, height): # 4-connected
        l = [[0 for _ in xrange(width)] for _ in xrange(height)]
    
        p = [0] # Parent array.
        label = 1
        # Assumption: 'a' has been padded with zeroes (bottom and right parts
        # does not require padding).
        for y in xrange(1, height):
            for x in xrange(1, width):
                if a[y][x] == 0:
                    continue
    
                # Decision tree for 4-connectivity.
                if a[y - 1][x]: # b
                    if a[y][x - 1]: # d
                        l[y][x] = union(p, l[y - 1][x], l[y][x - 1])
                    else:
                        l[y][x] = l[y - 1][x]
                elif a[y][x - 1]: # d
                    l[y][x] = l[y][x - 1]
                else:
                    # new label
                    l[y][x] = label
                    p.append(label)
                    label += 1
    
        return l, p
    

    所以最初你有一个数组a,你传递给这个函数scan。这是第一次贴标。要解析标签,只需拨打flatten_label(p)即可。然后第二次标记过程是一个微不足道的过程:

    for y in xrange(height):
        for x in xrange(width):
            l[y][x] = p[l[y][x]]
    

    现在您的4个连接组件已被标记,max(p)表示您拥有的组件数量。如果你沿着这段代码阅读论文,你应该没有理解它。语法来自Python,如果您对其含义有任何疑问,请随意提问。

答案 1 :(得分:0)

如果我对您的问题的理解是正确的,您可以使用floodfill来解决问题。