给定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>
答案 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);
}
}
}
算法说明:
答案 4 :(得分:0)
如果您知道群组的数量或想要将数据拟合到静态的群组数量,您可以使用k-means。