【问题标题】:Two (or more) dimensional dynamically created arrays in C++C++ 中的二维(或更多)维动态创建的数组
【发布时间】:2011-11-14 13:47:08
【问题描述】:

我正在实现一个动态编程算法,它需要在开始之前创建一些二维内存(内存的大小取决于参数,这些参数也没有明确的上限)。我尝试使用普通的 2-dim C++ 数组,但显然我不知道前面的第二维,所以它不起作用。实现它的最合理方法是什么?标准库或 boost 中是否有任何类可以使其尽可能简单?

我需要的功能相当基本:创建 MxN,获取或设置矩阵[i][j]

【问题讨论】:

    标签: c++ arrays multidimensional-array matrix


    【解决方案1】:

    唯一让我印象深刻的是丑陋的方式:将其实现为单维数组,然后手动执行双索引,例如:

    value = arr[i*num_i + j];
    

    你总是可以写一个类来隐藏丑陋...

    【讨论】:

    • 增加num_i 也会有点讨厌,但如果这也封装在类中,这是一个合理的解决方案。
    • +1 对于至少不提倡向量/向量数组的人。我不知道为什么人们在听到二维数组时总是想要那个?是你定义维度而不是内存布局。
    • 建议的方法已在多个 C++ 矩阵库中成功实现,所有丑陋的东西都隐藏在用户面前。最近的一个例子是Armadillo library
    【解决方案2】:

    您可以采用的最基本方法就是使用 std::vectors 数组。然后,您可以随时调整向量的大小。

    此外,如果您可以推迟创建数组,直到您知道两个维度,您可以使用 boost.MultiArray。我认为这可能是您正在寻找的更多内容。

    【讨论】:

    • 这就是我现在所做的,但是我需要记住调整 N 个独立向量的大小,这有点代码味道。
    • 刚刚写了相同的答案并删除了它,我同意内森的观点。在每个向量中保留空间是微不足道的 - 只需在数组中使用一个循环,直到您用于创建它的恒定大小。这是 2 行代码,它会处理每个向量 - 你希望它的效率提高多少>?如果您在创建向量数组时不知道第二维大小,则无法真正使用任何技巧。如果您想要更简单的东西,那么只需在堆上动态分配内存 - 但这并没有更好:)
    • 我同意你的代码气味。可能你最好的选择就是把它包装在你自己制作的一个类中(我们在这里谈论的可能是 10 行代码)。大多数处理矩阵的库都是线性代数。他们可能不支持动态调整矩阵大小。
    【解决方案3】:

    一个非常简单的二维数组只需要几行代码

    template<typename T>
    struct Matrix2d
    {
        int rows, cols;
        std::vector<T> data;
        Matrix2d(int rows, int cols) : rows(rows), cols(cols), data(rows*cols)
        { }
    
        T operator()(int i, int j) const { return data[i*cols+j]; }
        T& operator()(int i, int j) { return data[i*cols+j]; }
    };
    

    使用mat(i, j) 读取元素和mat(i, j) = v 写入元素访问。

    正如 James Kanze 针对二维数组的特殊情况所建议的那样,使用 operator[] 而不是 operator() 来获取 C++ 标准数组语法 mat[i][j]mat[i][j] = v 进行元素访问也很容易:

        T* operator[](int i) { return &data[i*cols]; }
        const T* operator[](int i) const { return &data[i*cols]; }
    

    但是,使用此解决方案,它会更难扩展到更多的维度(mat(i, j, k) 表示法的一个小问题)。

    【讨论】:

    • 这是一种解决方案(我并不是说它是错误的)。另一种可能性是定义operator[]( int i ) { return &amp;data[i * cols]; }(及其const等价物);这支持经典的m[i][j] 表示法(但需要引入代理来处理边界检查或大于 2 的尺寸)。
    • 我想过,但是将相同的方法扩展到更高维度会很烦人;这段代码可以简单地扩展。更通用的解决方案是 IMO 将存储与访问器分开。这将支持共享子矩阵,在这种情况下,一切都变得更加统一(mat[i] 是一个 (n-1) 维矩阵),并且还允许其他好东西(例如处理子矩阵,甚至例如奇数列的子矩阵) .有了更多的技巧,可以写mat[ANY][i]来表示在第二维上切片......等等等等...... :-D
    • 恕我直言,选择应该基于所需的语法,而不是编写一个基本类的难易程度。至于所需的语法,当然,这真的是一个品味问题;没有一个正确的答案。
    【解决方案4】:

    如果您不打算复制太多,或者不介意复制的开销,那么在这里使用向量似乎是一个好主意。此代码未经测试,可能不是 100% 正确)

    typedef std::vector< std::vector< int > > 2dVector;
    
    2dVector vec( 2 );
    vec[ 0 ].resize( someSize );
    vec[ 1 ].resize( someSize );
    
    vec[ 0 ][ 0 ] = 100;
    //Keep on doing stuff here.
    

    或者,您可以使用 boost::shared_array(或 tr1/c++11 等价物)来动态分配您的数组(此代码也未经测试,可能不正确):

    typedef boost::shared_array< boost::shared_array< int > > 2dArray;
    
    2dArray arr( new boost::shared_array< int >( firstDimensionSize ) );
    BOOST_FOREACH( boost::shared_array< int >& inner, arr )
    {
       inner = new int[ secondDimensionSize ];
    }
    
    arr[ 0 ][ 1 ] = 100;
    

    编辑:快速谷歌也揭示了boost multidimensional array 库。我没用过,也没有看太多描述,但也许值得研究一下

    【讨论】:

      猜你喜欢
      • 2020-05-20
      • 2020-07-25
      • 2013-02-22
      • 2011-08-14
      • 2018-05-19
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      相关资源
      最近更新 更多