在3d矩阵中找到最大值

时间:2012-01-13 21:27:06

标签: c# 3d matrix max

我有三维矩阵(n * m * k)。我试图通过搜索k维度来计算每个n和m的最大数量。((我试图找到每个n和m的k维度的最大数量))并且最后我有一个2d矩阵(n * m) )。我有以下代码,但它太慢了。是否有任何新代码或对当前代码的任何更改,以便更快地执行此操作。

感谢。

我的c#代码:注意:li是3维矩阵,它们更大或等于零。

int[,] array2 = new int[n, m];   
int[,] array = new int[n, m];
 List<Array> li = new List<Array>();             
for(int k = 0; k <'not a specific value, change each time' ; k++)
   { 
     li.Add(array);
     %% changing array
   } %% so li will became a (n*m*k) matrix   

for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                {
                    int ma = -2;
                    int d = 0;
                    while (d <= k)
                    {
                        ma = Math.Max(ma, Convert.ToInt32(li[d].GetValue(i, j)));
                        d++;
                    }
                    array2[i, j] = ma;
                }

4 个答案:

答案 0 :(得分:1)

最大的性能问题是您使用Array个对象作为列表的元素。这使得每个元素都使用GetValue框来访问该值,即分配一个新的微小对象来保存元素值。

如果替换

,您的代码运行速度会快很多
List<Array> li = new List<Array>();

List<int[,]> li = new List<int[,]>();

ma = Math.Max(ma, Convert.ToInt32(li[d].GetValue(i, j)));

ma = Math.Max(ma, li[d][i, j];

由于您事先不知道第3维,因此使用3D数组会更难。

完全不同的方法是在构建列表li时计算最大值。这有两个方面的帮助:1。您避免索引到数组列表和2.只要mn不是太大,就可以改善地点。也就是说:您正在使用的值在内存中更紧密,并且更可能位于处理器缓存中。

答案 1 :(得分:0)

这应该可以解决问题(即使它可能比你的方法慢一些):

// put this at the top of your source file
using System.Linq;

// put this where you calculate the maxima
for(int i = 0; i < array2.GetLength(0); ++i)
for(int j = 0; j < array2.GetLength(1); ++j)
{
    array2[i, j] = Convert.ToInt32(li.Max(x => x.GetValue(i, j)));
}

答案 2 :(得分:0)

从算法的角度来看,没有更有效的方法来评估所有k的固定n,m的最大值。这将需要O(n * m * k)操作。

现在,提高性能的唯一方法是在实现中找到改进,特别是在存储3D矩阵时。

使用List<Array>是一个需要改进的主要方面。您很容易出现装箱问题(将原始类型转换为对象)以及进行比必要更多的函数调用。

将3D矩阵缩小为原始数组:

int[] my3DArray = new int[n * m * l]; // Note I'm using l where you use k 

现在使用以下偏移量在[i,j,k]处索引数组:

int elementAtIJK = my3DArray[i + (n * j) + (m * n * k)];

如果您只使用基元数组,您应该会看到明显的改进。

修改

事实上,在C#(以及其他几种语言)中,直接实现3D数组非常容易,例如:

   int[,,] my3DArray = new int[n,m,l];
   int elementAtIJK = my3DArray[i,j,k];

这比我最初描述的要简单得多(但在一天结束时内部翻译为1D形式)。

如果第三维尺寸变化怎么办......

现在,如果第三维的大小变化很大,它会变得更有趣。如果它具有已知最大值并且不是太大,则可以将其设置为最大值并使用零填充空值。这很简单,可以满足您的需求。

但是,如果第三维可能非常大,那么所有这些额外存储的零可能会浪费大量宝贵的空间,您需要的是Sparse Matrix表示。

稀疏矩阵有不同的存储机制。出于您的目的,您可以将3D阵列视为2D矩阵,具有(n * m)行和max(k)列。由于第三维的长度不同,因此列中有很多空白区域。这称为稀疏行,标准数据存储为“压缩稀疏行”。同样,为了性能,这可以仅由三个原始数组,数据数组,行索引数组和列指针数组表示。网络上的其他资源可以比我更好地描述CSR实施,但希望这会指出您正确的方向。

答案 3 :(得分:0)

您可以使用这样的三维数组:

int xRange = 10;
int yRange = 10;
int zRange = 10;

int[, ,] matrix = new int[xRange, yRange, zRange];

// set up some dummy values
for (int x = 0; x < xRange; x++)
    for (int y = 0; y < yRange; y++)
        for (int z = 0; z < zRange; z++)
            matrix[x, y, z] = x * y * z;

// calculate maximum values
int[,] maxValues = new int[xRange, yRange];

/* LINQ version of maximum calculation
for (int x = 0; x < xRange; x++)
    for (int y = 0; y < yRange; y++)
        maxValues[x, y] = Enumerable.Range(0, zRange).Select(z => matrix[x, y, z]).Max();
*/

// longhand version of maximum calculation
for (int x = 0; x < xRange; x++)
    for (int y = 0; y < yRange; y++)
        for (int z = 0; z < zRange; z++)
            maxValues[x, y] = Math.Max(maxValues[x, y], matrix[x, y, z]);

// display results
for (int x = 0; x < xRange; x++)
{
    for (int y = 0; y < yRange; y++)
        Console.Write("{0}\t", maxValues[x, y]);
    Console.WriteLine();
}