简体   繁体   English

在3D矩阵中找到最大值

[英]finding maximum in a 3d matrix

I have matrix with 3 dimension (n*m*k). 我有3维(n * m * k)的矩阵。 I am trying to fined the maximum number for each n and m by searching in k dimension.((I try to find the maximum number in k dimension for each n and m)) and at last i have a 2d matrix (n*m). 我试图通过搜索k维来罚款每个n和m的最大数目。((我试图找到每个n和m在k维的最大数目))最后我有一个二维矩阵(n * m )。 i have the following code but it is so slow. 我有以下代码,但它是如此缓慢。 Is there any new code or any changes to the current code that do this more quickly. 是否有任何新代码或对当前代码的任何更改可以更快地完成此操作。

thanks. 谢谢。

my c# code: note: li is the 3 dimension matrix and they are grater or equal to zero. 我的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;
                }

The biggest performance issue is that you use Array objects as elements of your list. 最大的性能问题是您将Array对象用作列表的元素。 This makes it so that every element access using GetValue boxes the value, ie allocates a new tiny object to hold the element value. 这样一来,使用GetValue每个元素访问都将框值,即分配一个新的小对象来保存元素值。

Your code will run a lot faster if you replace 如果替换,您的代码将运行得更快

List<Array> li = new List<Array>();

with

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

and

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

with

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

Since you don't know the 3rd dimension in advance, it is harder to use 3D arrays. 由于您事先不知道第3维,因此使用3D阵列会比较困难。

An entirely different approach would be to compute the maximum as you're building the list li . 一种完全不同的方法是在构建列表li计算最大值。 This will help in two ways: 1. You avoid indexing into the list of arrays and 2. as long as m and n aren't too large, you improve locality. 这将以两种方式提供帮助:1.避免索引到数组列表中;以及2.只要mn不太大,就可以改善局部性。 That is: the values you're working with are closer together in memory, and more likely to be in the processor cache. 那就是:您正在使用的值在内存中更靠近,并且更有可能在处理器缓存中。

This should do the trick (even though it could be kinda slower than your approach): 这应该可以解决问题(尽管它可能比您的方法要慢一些):

// 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)));
}

From an algorithm perspective, there's no more efficient way to evaluate the maximum value for fixed n,m for all k. 从算法角度来看,没有更有效的方法来评估所有k的固定n,m的最大值。 It will take O(n*m*k) operations. 这将需要O(n * m * k)个运算。

Now, the only way to improve performance is to find improvements in your implementation, particularly in your storage of the 3D matrix. 现在,提高性能的唯一方法是在实现中找到改进,特别是在3D矩阵的存储中。

Using List<Array> is a major area for improvement. 使用List<Array>是需要改进的主要领域。 You are prone to boxing issues (conversion of primitive types to objects) and making more function calls than are necessary. 您很容易出现装箱问题(将原始类型转换为对象),并且进行过多的函数调用。

Reduce your 3D matrix to an array of primitives: 将您的3D矩阵简化为原始数组:

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

Now index into your array at [i, j, k] using the following offset: 现在,使用以下偏移量在[i,j,k]处索引到您的数组中:

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

If you just use arrays of primitives you should see a definite improvement. 如果仅使用基元数组,则应该看到一定的改进。

Edit: 编辑:

In fact, in C# (and several other languages) it's very easy to implement 3D arrays directly , eg: 实际上,在C#(和其他几种语言)中, 直接实现3D数组非常容易,例如:

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

Which is much simpler than I first described (but at the end of the day is internally translated in the 1D form). 这比我最初描述的要简单得多(但最终以1D形式在内部进行翻译)。

What to do if the 3rd dimension varies in size... 如果第三维尺寸不同怎么办...

Now, it gets more interesting if the size of the 3rd dimension varies significantly. 现在,如果第3维的大小发生显着变化,它将变得更加有趣。 If it has a known maximum and isn't too big, you can simply set it to the maximum and fill the empty values with zeroes. 如果它具有已知的最大值,但又不是太大,则可以将其设置为最大值,然后用零填充空白值。 This is simple and may meet your needs. 这很简单,可以满足您的需求。

However, if the 3rd dimension can be very big, all these extra stored zeroes could waste a lot of valuable space and what you need is a Sparse Matrix representation. 但是,如果第3维可能很大,那么所有这些额外存储的零都可能浪费大量宝贵的空间,而您需要的是稀疏矩阵表示。

There are different storage mechanisms for sparse matrices. 稀疏矩阵有不同的存储机制。 For your purposes, you could consider your 3D array to be a 2D matrix, with (n*m) rows and max(k) columns. 出于您的目的,您可以将3D数组视为具有(n * m)行和max(k)列的2D矩阵。 As the 3rd dimension varies in length, there are lots of empty spaces in your columns. 由于第3维的长度不同,因此列中有很多空白。 This is called a sparse row and the standard data storage for this is "Compressed Sparse Row". 这称为稀疏行,其标准数据存储为“压缩稀疏行”。 Again, for performance this can be represented just by three primitive arrays, a data array, a row index array and a column pointer array. 同样,为了提高性能,可以仅由三个基本数组,一个数据数组,一个行索引数组和一个列指针数组表示。 There are resources elsewhere on the web that describe the CSR implementation better than I can, but hopefully this will point you in the right direction. 网络上其他地方的资源比我能更好地描述CSR的实现,但是希望这会为您指明正确的方向。

You could use a three-dimensional array like this: 您可以使用这样的三维数组:

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM