【问题标题】:dynamical two dimension array according to input根据输入的动态二维数组
【发布时间】:2011-01-14 00:48:15
【问题描述】:

我需要从用户那里得到一个输入 N 并生成一个 N*N 矩阵。如何声明矩阵?一般来说,数组和矩阵的大小应该在声明时就固定了,对吧? vector<vector<int>> 呢?我以前从未使用过这个,所以我需要资深人士的建议。

【问题讨论】:

  • [c] 中的动态多维数组已经讨论过好几次了,这种风格也是可用的。

标签: c++ vector matrix multidimensional-array


【解决方案1】:

vector<vector<int>>(或 vector<vector<int> >,对于较旧的编译器)可以很好地工作,但它不一定是最有效的方法1。另一个可以很好地工作的是单个向量的包装器,它跟踪所表示的矩阵的“形状”,并提供一个函数或重载运算符来访问数据:

template <class T>
class matrix { 
    int columns_;
    std::vector<T> data;
public:
    matrix(int columns, int rows) : columns_(columns), data(columns*rows) {}

    T &operator()(int column, int row) { return data[row*columns_+column]; }
};

请注意,C++ 标准只允许operator[] 采用单个操作数,因此您不能将它用于这项工作,至少不能直接使用。在上面的示例中,我(显然)使用了operator(),所以下标看起来更像 Fortran 或 BASIC,而不是您在 C++ 中所习惯的。如果你真的打算使用[] 表示法,无论如何你都可以这样做,尽管它有点棘手(你在矩阵类中重载它以返回代理,然后让代理类也重载operator[] 以返回(a参考)正确的元素——它在内部有点难看,但无论如何工作得很好)。

这是一个如何使用operator[] 的多个重载来实现版本的示例。我在大多数编译器包含std::vector 之前写了这个(很长一段时间),所以它静态分配一个数组而不是使用一个向量。它也适用于 3D 案例(因此涉及到两个级别的代理),但幸运的是,基本的想法还是通过了:

template<class T, int size>
class matrix3 {

    T data[size][size][size];

    friend class proxy;
    friend class proxy2;

    class proxy { 
        matrix3 &m_;
        int index1_, index2_;
    public:
        proxy(matrix3 &m, int i1, int i2) 
            : m_(m), index1_(i1), index2_(i2) 
        {}

        T &operator[](int index3) { 
            return m_.data[index1_][index2_][index3];
        }
    };

    class proxy2 { 
        matrix3 &m_;
        int index_;
    public:
        proxy2(matrix3 &m, int d) : m_(m), index_(d) { }

        proxy operator[](int index2) { 
            return proxy(m_, index_, index2);
        }
    };
public:
    proxy2 operator[](int index) {
        return proxy2(*this, index);
    }
};

使用它,您可以使用正常的 C++ 语法来寻址矩阵,例如:

matrix3<double, size> m;

for (int x=0; x<size; x++)
    for (int y = 0; y<size; y++)
        for (int z = 0; z<size; z++)
            m[x][y][z] = x*100 + y * 10 + z;

  1. std::vector 通常实现为指向一些动态分配的数据的指针,因此像vector&lt;vector&lt;vector&lt;int&gt;&gt;&gt; 这样的东西将取消引用两级指针以获取每条数据。这意味着更多的内存引用,这在大多数现代处理器上往往相当慢。由于每个向量都包含单独分配的数据,因此通常也会导致缓存局部性不佳。它也可能会浪费一些空间,因为每个向量都存储其分配的大小和正在使用的大小。

【讨论】:

  • 想弄清楚向量的向量的低效率部分吗?
  • @Murali:基本上,您在几个方面效率低下。首先,即使所有子向量(可以这么说)都将具有相同的大小,但每个子向量都存储自己的长度。其次,向量(至少通常)是使用指向动态分配数据的指针来实现的,因此对于向量向量,您需要通过两个级别的指针来获取真实数据。使用单个向量反而涉及乘法,这曾经是一个糟糕的权衡,但由于 CPU 比内存更快,现在几乎总是一个胜利(额外的 CPU 时间与额外内存访问的可能性)。
  • 你也可以使用 std::valarray 因为它已经支持各种子集访问机制。
  • @MSN:你可以——valarray 是我过去多次提到的,但坦率地说,这是我决定不再挥舞的横幅。简单地使用它可能是有意义的,但是一旦你进入 slice、gslice、slice_array 等,它就变得对至少 99% 的 C++ 社区完全不透明。更糟糕的是,它实际上是为矢量处理器设计的;它对缓存相对不友好,所以即使你知道它在做什么,而且读者也知道,这通常是一种非常低效的方式。
  • 但是想想你会节省的所有打字! :)
【解决方案2】:

示例代码:

template<class T>
class Array2D
{
public:
    Array2D(int a, int b)  
    {
        num1 = (T**)new int [a*sizeof(int*)];
        for(int i = 0; i < a; i++)
            num1[i] = new int [b*sizeof(int)];

        for (int i = 0; i < a; i++) {
            for (int j = 0; j < b; j++) {
                num1[i][j] = i*j;
            }
        }
    }
    class Array1D
    {
    public:
        Array1D(int* a):temp(a) {}
        T& operator[](int a)
        {
            return temp[a];
        }
        T* temp;
    };

    T** num1;
    Array1D operator[] (int a)
    {
        return Array1D(num1[a]);
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    Array2D<int> arr(20, 30);

    std::cout << arr[2][3];
    getchar();
    return 0;
}

    enter code here

【讨论】:

    【解决方案3】:

    Boost 在其uBLAS library 中实现了矩阵(支持数学运算),并提供如下使用语法。

    #include <boost/numeric/ublas/matrix.hpp>
    
    int main(int argc, char* argv[])
    {
        unsigned int N = atoi(argv[1]);
        boost::matrix<int> myMatrix(N, N);
    
        for (unsigned i = 0; i < myMatrix.size1 (); ++i)
            for (unsigned j = 0; j < myMatrix.size2 (); ++j)
                myMatrix(i, j) = 3 * i + j;
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-16
      • 2019-01-12
      • 1970-01-01
      • 2022-11-25
      • 2018-02-28
      • 2013-10-03
      • 2017-07-14
      • 1970-01-01
      相关资源
      最近更新 更多