给定2D数组,找到簇

时间:2011-12-29 06:49:45

标签: algorithm matrix

给定2D数组,例如:

0 0 0 0 0
0 2 3 0 1
0 8 5 0 7
7 0 0 0 4

输出应该是群组:

群集1:<2,3,8,5,7>

群集2:<1,7,4>

5 个答案:

答案 0 :(得分:5)

您的问题似乎是找到连接的组件。您应该使用遍历方法(BFS或DFS将完成工作)。迭代所有元素,为每个非零元素启动一个遍历并记录您在该遍历中看到的所有元素并将每个被访问元素转换为零。类似下面的代码:

void DFS(int x, int y)
{
  printf("%d ", g[x][y]);
  g[x][y] = 0;
  // iterate over neighbours
  for(dx=-1; dx<=1; dx++)
    for(dy=-1; dy<=1; dy++)
      if (g[x+dx][y+dy]) DFS(x+dx, y+dy);
}

for(i=0; i<n; i++)
  for(j=0; j<n; j++)
    if (g[i][j])
    {
      DFS(i, j);
      printf("\n");
    }

答案 1 :(得分:2)

一种方法是使用图表。以某种顺序遍历矩阵(我从左到右,从上到下)。遇到非零元素时,将其添加到图表中。然后检查它的所有邻居(看起来你想要8个连接的邻居),并且对于每个非零的邻居,将其节点添加到图中,并将其连接到当前元素。图表中的元素可能必须跟踪其坐标,以便您可以查看是否添加了重复项。当您完成遍历矩阵时,您将拥有一个包含一组聚类的图表。集群应该是连通元素的子图。

答案 2 :(得分:2)

您想要Connected Component Labeling。这通常被认为是一种图像处理算法,但它符合您的描述。

你也会得到K-means的建议,因为你说 2D数组,很容易将其解释为 2D数字。 K-means在平面中找到点簇,而不像您请求的那样在2D数组中找到连接的组。

答案 3 :(得分:1)

代码示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Practice
{
    class Program
    {
        static void Main()
        {
            var matrix = new[] { new StringBuilder("00000"), new StringBuilder("02301"), new StringBuilder("08507"), new StringBuilder("70004") };
            var clusters = 0;
            for (var i = 0; i < matrix.Length; i++)
                for (var j = 0; j < (matrix.Any() ? matrix[i].Length : 0); j++)
                    if (matrix[i][j] != '0')
                    {
                        Console.Write("Cluster {0}: <", ++clusters);
                        var cluster = new List<char>();
                        Traverse(matrix, i, j, ref cluster);
                        Console.WriteLine("{0}>", string.Join(",", cluster));
                    }
            Console.ReadKey();
        }

        private static void Traverse(StringBuilder[] matrix, int row, int col, ref List<char> cluster)
        {
            cluster.Add(matrix[row][col]);
            matrix[row][col] = '0';
            for (var i = -1; i <= 1 && row + i >= 0 && row + i < matrix.Length; i++)
                for (var j = -1; j <= 1 && col + j >= 0 && col + j < (matrix.Any() ? matrix[row + i].Length : 0); j++)
                    if(matrix[row + i][col + j] != '0')
                        Traverse(matrix, row + i, col + j, ref cluster);
        }
    }
}

算法说明:

  • 每行:
    • 对于该行中的每一列:
      • 如果该项目是未访问的非零:
        1. 保存找到的群集成员;
        2. 将[行,列]的位置标记为已访问;
        3. 在保持矩阵的入界时检查任何未访问的非零邻居:
          • [row - 1,column - 1];
          • [row - 1,column];
          • [row - 1,column + 1];
          • [row,column - 1];
          • [row,column + 1];
          • [row + 1,column - 1];
          • [row + 1,column];
          • [row + 1,column + 1]。
        4. 如果任何邻居是未访问的非零,则递归地重复步骤1-4,直到所有邻居都被访问为零(已找到所有集群成员)。

答案 4 :(得分:0)

如果您知道群组的数量或想要将数据拟合到静态的群组数量,您可以使用k-means。

http://en.wikipedia.org/wiki/K-means_clustering