代码之家  ›  专栏  ›  技术社区  ›  Lisa Ann

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

  •  0
  • Lisa Ann  · 技术社区  · 11 年前

    给你来一杯 std::vector< T > (其中 T 我是指包含 n 元素,并且您希望填充类似矩阵的对象,例如类的对象 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());
            }
        }
    }
    

    一个快速的main尝试它:

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

    重点是:我缺少了一些对索引的简单操作,以实现相同的结果,我在搞乱索引。

    1 回复  |  直到 11 年前
        1
  •  1
  •   Mercious    11 年前

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

    同样,您遇到的问题是:

    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,你将永远重写为值为1的矩阵i1索引。 然后,如果j大于2*size2,您将尝试写出绑定标记。例如,如果vecor包含20个元素,并且您有一个7*7矩阵,那么当vectorIndex变为8时,您将立即写入vectorIndex-7。[请注意,您的<=tMatrix.size2()也是错误的,应仅为<)。这一直有效,直到vectorIndex为14或更大,如14-7=7或更大->超出范围。

    第二个问题是,外部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做些什么!