【问题标题】:Algorithm to visit all points in a matrix of N (unknown) dimensions访问 N(未知)维矩阵中所有点的算法
【发布时间】:2011-04-03 08:57:36
【问题描述】:

我有一个多维矩阵,它的维数可以大于一。寻找一种可以访问矩阵中每个点的高效算法。

关于代码的一些信息: 该矩阵具有类似的值访问器(尽管这些并不真正相关)。

object value = matrixInstance.GetValue(int[] point);   
matrixInstance.SetValue(object value, int[] point);  

注意:参数 point 是索引数组,必须匹配 # 个维度,否则会引发异常。

可以通过以下方式获取有关矩阵结构的信息:

int numDims = matrixInstance.Rank; //# dimensions
int sizeDim = matrix.getRankSize(int index); // length of specified dimension

我想使用相对有效的算法迭代矩阵的所有可能点。

例如,在 2x3 2D 矩阵中,将访问以下六个点:
[0,0] [0,1] [0,2] [1,0] [1,1] [1,2]

算法必须工作到 N 维:2、3、4 等。为了提高效率,我最终将使用C# iterator 来返回积分。

【问题讨论】:

    标签: c# algorithm c#-3.0 matrix traversal


    【解决方案1】:

    您可以将矩阵查看为一棵树,其所有值都位于叶子上:

               

    是矩阵

    [0,0] = 'A'
    [0,1] = 'B'
    [1,0] = 'C'
    [1,1] = 'D'
    

    只需应用任何众所周知的树遍历解决方案。


    这是一个递归解决方案(未经测试):

    IEnumerable<Point> GetPoints(Matrix matrix, int[] indexes)
    {
        if (indexes.Length == matrix.Rank)
        {
            yield return matrix.GetValue(indexes);
        }
        else
        {
            for (int i = 0; i < matrix.GetRankSize(indexes.Length); i++)
            {
                foreach (var point in
                    GetPoints(matrix, indexes.Concat(new int[] { i }).ToArray())
                {
                    yield return point;
                }
            }
        }
    }
    

    将其转换为使用显式堆栈的迭代版本应该相当简单。

    【讨论】:

    • 我最终使用了递归函数,然后将其转换为您提到的基于堆栈的实现。但是我从头开始编写代码,因此您的代码仍未经过测试。
    【解决方案2】:

    如果您可以在运行时为每个维度生成索引值的集合,那么您可以使用Eric Lippert's LINQ snippet 来生成索引值的所有组合。

    Eric 产生所有组合的集合的方法:

    static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) 
    { 
      IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
      return sequences.Aggregate( 
        emptyProduct, 
        (accumulator, sequence) =>  
          from accseq in accumulator  
          from item in sequence  
          select accseq.Concat(new[] {item}));                
    }
    

    因此,对于您的 2x3 示例,

    int [ , ] dimensions= { { 0, 1}, { 0, 1, 2 } } ;
    var allMatrixCells = CartesianProduct<int>(dimensions);
    
    foreach(var cellLocation in allMatrixCells )
    {
     ...
    }
    

    【讨论】:

    • 哈哈。我只是在研究完全相同的解决方案。干得好:)
    【解决方案3】:

    简单地递归迭代每个维度。例如,第一次调用迭代第一个维度的每个值,调用自身迭代第二个维度的每个值,等等,无论您拥有多少维度。然后,基本情况(当没有更多维度时)是返回相关单元格中的值,而不是再次递归。

    【讨论】:

      【解决方案4】:

      您可以使用混合基数表示,例如http://en.wikipedia.org/wiki/Mixed_radix

      例如,如果您有 4 个维度,长度为 4,3,2,7,那么对应于索引 a,b,c,d 我们有数字 a+4*(b+3*(c+2* d))。从 一个数字 n 就像得到十进制数字一样,除了基数不同,即 a = n%4; n /=4; b = n%3; n /= 3; c = n %2; n/=2; d = n。

      因此,您将有一个 for 循环(在本例中为 n=0..4*3*2*7-1),其中索引可以 如上所述从 n 中恢复。

      但也许所有这些除法和模数都意味着这不是那么有效。

      【讨论】:

        猜你喜欢
        • 2018-12-25
        • 2013-06-23
        • 2015-04-30
        • 2012-04-26
        • 1970-01-01
        • 2014-12-13
        • 2018-03-30
        • 2012-11-04
        • 2011-08-08
        相关资源
        最近更新 更多