按行、列或随机从数组填充矩阵时出现错误索引问题

Bad index issues while populating a matrix from an array by rows, columns or randomly

让你有一个包含 n 元素的 std::vector< T >T 我的意思是任何 class 或类型名称)并且你想要填充一个类似矩阵的对象,例如 class boost::numeric::ublas::matrix< T > 的对象,其维度为 m1 行和 m2 列,逐行或逐列逐个插入这些元素。

首先,它必须是 n <= m1 * m2 或者我们试图用 11 个或更多元素填充,比方说,10 个槽位;然后:如果n <= m1(分别为n <= m2)循环就足够了。

但是如果 n > m1 (n > m2) 你必须拆分你的 std::vector< T > 以避免糟糕的索引问题并根据你的选择填充你的矩阵。

这是我的尝试:

#include <algorithm>
#include <boost/numeric/ublas/matrix.hpp>
#include <vector>

template < class T > inline void PopulateGrid(const std::vector< T >& tVector,
                                              boost::numeric::ublas::matrix< T >& tMatrix,
                                              char by = 'n')
{
    if (tVector.size() > tMatrix.size1() * tMatrix.size2())
        throw("Matrix is too small to contain all the array elements!");
    else
    {
        switch(by)
        {
        case 'r' :
            for (unsigned i = 0; i < tMatrix.size1(); i++)
            {
                for (unsigned j = 0; j < tVector.size(); j++)
                {
                    if (j <= tMatrix.size2())
                        tMatrix(i, j) = tVector[j];
                    else
                        tMatrix(i + 1, j - tMatrix.size2()) = tVector[j];
                }
            }
            break;
        case 'c' :
            for (unsigned j = 0; j < tMatrix.size2(); j++)
            {
                for (unsigned i = 0; i < tVector.size(); i++)
                {
                    if (i <= tMatrix.size1())
                        tMatrix(i, j) = tVector[i];
                    else
                        tMatrix(i - tMatrix.size1(), j + 1) = tVector[j];
                }
            }
            break;
        default:
            for (unsigned i = 0; i < tMatrix.size1(); i++)
            {
                for (unsigned j = 0; j < tVector.size(); j++)
                {
                    if (j <= tMatrix.size2())
                        tMatrix(i, j) = tVector[j];
                    else
                        tMatrix(i + 1, j - tMatrix.size2()) = tVector[j];
                }
            }
            // Following is just to populate it randomly
            std::random_shuffle(tMatrix.begin1(), tMatrix.end1());
            std::random_shuffle(tMatrix.begin2(), tMatrix.end2());
        }
    }
}

快速主试一下:

int main()
{
    std::vector< int > ciao;
    for (int i = 0; i < 12; i++)
        ciao.push_back(i);
    boost::numeric::ublas::matrix< int > peppa(10, 10);
    PopulateGrid< int >(ciao, peppa); // crashes!

   /* Check failed in file C:\DevTools\boost_1_54_0/boost/numeric/ublas/functional.hpp
    * at line 1371:
    *    j < size_j
    * terminate called after throwing an instance of 'boost::numeric::ublas::bad_index'
    *    what():  bad index
    */

    return 0;
}

重点是:我错过了一些更简单的索引操作来获得相同的结果,而且我正在弄乱索引。

我会完全重写这个答案,现在它更多的是一个答案而不是一个建议。

同样,您遇到的问题是:

for (unsigned j = 0; j < tVector.size(); j++) {
  if (j <= tMatrix.size2())
    tMatrix(i, j) = tVector[j];
  else
    tMatrix(i + 1, j - tMatrix.size2()) = tVector[j];
}

这是您正在使用的嵌套 for 循环结构的内部循环。在这里,您 运行 遍历整个向量。当 j 超过 size2 时,您不会退出循环,而是将 (i+1) 作为 tMatrix(i1,i2) 的第一个索引。然后对于 i2,您从 j 中减去 size2。

两个问题:一旦你的 j 超过 size2 你将永远重写到矩阵 i1 索引值 1。 然后,如果 j 变得大于 2*size2,您将尝试写出边界索引。比如vecor包含20个元素,你有一个7*7的矩阵,你会在vectorIndex一变成8就写vectorIndex-7。【注意你的<=tMatrix.size2()也是错误的,应该是only < ).这一直有效,直到 vectorIndex 为 14 或更大,因为 14-7 = 7 或 great -> out of bound.

第二个问题是您的外部 for 循环仍将进行迭代并为每个 i 值调用整个过程。最后,您将达到允许的最大 i 值,并且在您的内部循环中,您将尝试访问 (i+1)。这也会给你一个超出范围的期望。

我会建议这样的解决方案:

for ( std::vector<T>::iterator it = yourVector.begin(), int rowIndex = 0, colmIndex = 0; 
      it != yourVector.end(); ++it, colmIndex++ ) {

      if ( colmIndex >= yourMatrix.size2() ) {
          rowIndex++;
          colmIndex = 0;
          yourMatrix (rowIndex, colmIndex ) = *it;
      }
      else {
          yourMatrix (rowIndex, colmIndex ) = *it;
      }

  }

这是未经测试的,按列填充向量。您应该能够自己弄清楚为 byRow 做什么!