将1D矩阵阵列转换为主1D矩阵的有趣算法挑战需要有效的解决方案

时间:2012-04-12 22:56:26

标签: c++ algorithm

两个typedef

std::vector<double> Matrix;
std::vector<Matrix> MatrixBlocks;

Matrix由1D向量表示,MatrixBlocks表示矩阵向量。

问题是,假设矩阵块包含来自具有特定排序的较大矩阵的子矩阵,我需要用矩阵块重建大矩阵。所以例如

假设大型矩阵(存储为std::vector<double>)具有以下数据:

 1  2  3  4 
 5  6  7  8
 9  10 11 12
 13 14 15 16

并且下面包含上述矩阵的子矩阵的MatrixBlocks具有以下数据:

索引0:

1 2
5 6

索引1:

3 4 
7 8 

索引2:

9 10 
13 14 

索引3:

11 12 
15 16

所以鉴于MatrixBlock我需要重建double的原始向量; 1D矩阵。有人有任何一般解决方案?

您可以假设,如果大型矩阵总是一个方形大小的矩阵。

编辑:

对于NxN矩阵,它被分解为K mxm矩阵,其中N可以对m进行整除,您可以假设MatrixBlock的顺序如下:

索引0:将包含从[0,0]到(m,m)

的矩阵

索引1:将包含从[0,m]到(m,m + m)

的矩阵

索引2:将包含从[0,m + m]到(m,m + m + m)的矩阵

...

直到最后一个索引包含从[m * i - m,m * i - m]到[m,m]

的矩阵

因此,例如,如果主矩阵是512x512

1 2 3 4 ... 512
513 ...   1014
 ...

261632(512 * 512-512)... 262144(512 * 512)

我们希望将512x512矩阵拆分为256个32x32块,用户选择32,然后MatrixBlock将包含类似

的内容

索引0:    1 2 3 ... 32    513 ... 513 + 32    //..up到第32行的列长度为32

索引1:  33 34 ...(33 + 32)  (513 + 32 + 1)......(513 + 32 + 1 + 32)  // ...与上面相同

所以你可以看到它从索引(0,0)开始,并从(0,0)到(31,31)提取第一个32x32元素;索引为0.然后对于索引1,起始位置为(0,32),它从矩形(0,32),(0,63),(31,32),(31,63)中提取数据< / p> 希望很清楚。因此,对于上面的4x4矩阵,基本上观察到的相同模式对于任何矩阵大小将是相同的模式,唯一的区别是主矩阵并不总是大小为4x4,并且我们将其分成的块大小并不总是2x2。

2 个答案:

答案 0 :(得分:2)

这基本归结为正确索引。

#include <cmath>
#include <iostream>
#include <vector>

int main()
{
  std::vector<double> v(16);
  std::vector<std::vector<double> > m;
  std::vector<double> m1 {1,2,5,6};
  m.push_back(m1);
  std::vector<double> m2 {3,4,7,8};
  m.push_back(m2);
  std::vector<double> m3 {9,10,13,14};
  m.push_back(m3);
  std::vector<double> m4 {11,12,15,16};
  m.push_back(m4);

  size_t idx = 0;
  for (size_t big_row = 0; big_row < std::sqrt(m.size()); ++big_row)
  for (size_t small_row = 0; small_row < std::sqrt(m1.size()); ++small_row)
  for (size_t big_col = 0; big_col < std::sqrt(m.size()); ++big_col)
  for (size_t small_col = 0; small_col < std::sqrt(m1.size()); ++small_col)
  {
    v[idx] = m[big_col + std::sqrt(m.size()) * big_row][small_col + std::sqrt(m1.size()) * small_row];
    ++idx;
  }

  for (unsigned i = 0; i < 16; ++i)
    std::cout << v[i] << std::endl;
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

答案 1 :(得分:1)

假设原始矩阵是大NxN,并且每个子矩阵是nxn。一侧的子矩阵的数量是(N / n);让我们称之为k。

我们可以将大矩阵看作一个长的n * k * n * k长度列表。

我们可以将大矩阵索引映射到子矩阵数和索引,反之亦然。前向映射似乎是非常复杂的,我只是通过首先写出我想要的子矩阵索引作为一个系列,然后编写一个函数来生成该系列(以及时间测试的试错法,当然)。

一些代码展示了第一种方法(请原谅尘埃):

#include <iostream>
#include <vector>

int main() {
  // Initialize the Vector and Set up the Matrices
  std::vector<double> v(36);
  std::vector<std::vector<double> > m;
  std::vector<double> m1 {1,2,7,8};
  m.push_back(m1);
  std::vector<double> m2 {3,4,9,10};
  m.push_back(m2);
  std::vector<double> m3 {5,6,11,12};
  m.push_back(m3);
  std::vector<double> m4 {13,14,19,20};
  m.push_back(m4);
  std::vector<double> m5 {15,16,21,22};
  m.push_back(m5);
  std::vector<double> m6 {17,18,23,24};
  m.push_back(m6);
  std::vector<double> m7 {25,26,31,32};
  m.push_back(m7);
  std::vector<double> m8 {27,28,33,34};
  m.push_back(m8);
  std::vector<double> m9 {29,30,35,36};
  m.push_back(m9);

  // These variables (see explanation above) take on these values for this example
  unsigned N = 6;
  unsigned n = 2;
  unsigned k = N/n;

  // Constructing the Big Matrix    
  for (unsigned i = 0; i < N*N; ++i) {
    int a = (i / (n * k * n)) * k + ((i / n) % k);
    int b = (i % (n * k * n)) % n + ((i % (n * k * n)) / (n * k) * n);
    v[i] = m[a][b];
    std::cout << a << "\t" << b << "\t" << v[i] << std::endl;
  }
}

我们还可以通过遍历子矩阵列表来处理反向映射,并将每个索引映射回大矩阵。我还没编码,但你明白了。

无论哪种方式,算法在所有情况下都应该花费O(N ^ 2)时间(N是大矩阵的一侧)。如果你让N是矩阵的大小,那么它就是线性时间。

这对您的申请来说是否足够有效?