2012-03-18 16 views
1

我想構建一個nx,ny,nz約爲200的3D nx * ny * nz矩陣,所以我必須使用動態分配,並且因爲我有很多這些矩陣,所以我需要以它使用的方式構建這些矩陣儘可能少的內存我怎麼能做到這一點,如何建立連續的形式?動態分配內存的3d陣列,使用最小的內存,並在C + +的連續形式?

+2

這些稀疏矩陣? – 2012-03-18 16:29:34

+3

你可能會考慮[Boost.MultiArray](http://www.boost.org/doc/libs/1_49_0/libs/multi_array/doc/index.html)。 – 2012-03-18 16:30:25

+0

元素是雙倍的。 – peaceman 2012-03-18 16:36:05

回答

1

您可以圍繞std::vector編寫一個包裝,並重載operator()來訪問矩陣元素。元素連續存儲在1D std::vector中,operator()將3D索引轉換爲std::vector中的1D索引。如果矩陣是2D,這是怎麼從2D到1D映射將如下所示:

| 1 2 3 | 
| 4 5 6 | ---> [1 2 3 4 5 6 7 8 9] 
| 7 8 9 | 

這種排序被稱爲row major

下面是重載operator()到3D指數轉換成一排,主要的一維指數類的例子:

#include <iostream> 
#include <vector> 

template <class T> 
class Matrix3D 
{ 
public: 
    Matrix3D(size_t m, size_t n, size_t o) 
    : m_(m), n_(n), o_(o), data_(m*n*o) {} 

    T& operator()(size_t i, size_t j, size_t k) 
    { 
     return data_[(i * n_ * o_) + (j * o_) + k]; 
    } 

    const T& operator()(size_t i, size_t j, size_t k) const 
    { 
     return data_[(i * n_ * o_) + (j * o_) + k]; 
    } 

private: 
    std::vector<T> data_; 
    size_t m_, n_, o_; 
}; 

int main() 
{ 
    Matrix3D<float> m(4, 3, 2); 
    m(0,0,0) = 12.3f; 
    m(3,2,1) = 45.6f; 
    std::cout << m(0,0,0) << " " << m(3,2,1) << "\n"; 
} 

Boost.MultiArray庫本質上是做同樣的事情,因爲這(和更多),但可可用於任何N維

+0

糟糕,應該是Boost.MultiArray,而不是Boost.MultiIndex。 – 2012-03-18 17:40:59

+0

您的代碼有分段錯誤錯誤 – peaceman 2012-03-18 18:46:03

+0

它在我的機器和Ideone.com上運行良好。我甚至嘗試過使用'vector :: at'而不是'vector :operator []'。請注意,指數是從零開始的。 – 2012-03-18 21:06:38

1

如果尺寸在編譯時已知,您可以使用new來分配對象,但我可能會把它放在一個結構中,因爲我在陣列和指針上保持混合類型(我幾乎沒有直接使用它們):

struct array3d { 
    double array[200][200][200]; 
}; 

std::auto_ptr<areay3d> array(new array3d); 

顯然,數組維度可以成爲模板參數。

如果僅在運行時確定尺寸,則需要分配一個連續的數組double並自己進行數組下標計算。如果類可以訪問元素,這可能也會成爲一個集合:3d數組的下標運算符將返回對2d數組的引用等。std::valarray<double>旨在幫助完成此操作,並且此類提升類也是如此。

+0

看到這個問題如何使用'std :: valarray'來表示一個連續的二維矩陣:http://stackoverflow.com/questions/2187648/how-can-i-use-a -stdvalarray-store-manipulation-a-contiguous-2d-array – 2012-03-18 17:30:48

+0

std :: auto_ptr被棄用... – 2012-03-18 20:07:05

+0

@RobertMason:的確如此。但是,它可用於所有當代C++實現,不同於'std :: unique_ptr ',它僅在支持右值引用的系統上可用。爲了自動刪除一個對象都工作得很好。因此,使用'std :: auto_ptr '似乎比'std :: unique_ptr '更合適。 – 2012-03-18 20:12:40

2

使用C++ 11:

template<typename T,size_t M,size_t N,size_t O> 
using Matrix3D = std::array<std::array<std::array<T,O>,N>,M>; 

std::unique_ptr<Matrix3D<double,200,200,200>> mat(new Matrix3D<double,200,200,200>); 

(*mat)[m][n][o] = 10.0; 

如果你寫一個make_unique功能VA聲明可變結構變爲:

auto mat = std::make_unique<Matrix3D<double,200,200,200>>(); 

所以整個節目看起來像:

#include <memory> // std::unique_ptr for convenient and exception safe dynamic-memory management 
#include <array> // std::array because it behaves much better than raw arrays 

template<typename T,size_t M,size_t N,size_t O> 
using Matrix3D = std::array<std::array<std::array<T,O>,N>,M>; 

// A simple `make_unique` 
template<typename T,typename... Args> 
std::unique_ptr<T> make_unique(Args&&... args) { 
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); 
} 

int main() { 
    auto mat = make_unique<Matrix3D<double,200,27,200>>(); 
    (*mat)[199][26][199] = 10.0; // store 10.0 in the last element 
} 

請記住,這是C++ 11,和一些編譯器還沒有實現所有的功能我正在使用。特別是我所知道的唯一支持模板別名的發佈編譯器(using Matrix3D =行)是鏗鏘3.0。 GCC的下一個版本將支持它。在GCC和Clang中均支持可變模板(用於實現make_unique),但在VS11中不支持MSVC。

下面是一個使用只有廣泛的支持* C++ 11功能版本:

#include <memory> 
#include <array> 

template<typename T,size_t M,size_t N,size_t O> 
struct Matrix3D { 
    std::array<std::array<std::array<T,O>,N>,M> array; 
}; 

// A simple `make_unique` that supports only zero-argument construction. 
template<typename T> 
std::unique_ptr<T> make_unique() { 
    return std::unique_ptr<T>(new T); 
} 

int main() { 
    auto mat = make_unique<Matrix3D<double,200,27,200>>(); 
    mat->array[199][26][199] = 10.0; // store 10.0 in the last element 
} 

*獲得廣泛支持的手段至少GCC和MSVC的最新版本。

+0

OP希望矩陣元素連續存儲。這些元素是否會與此解決方案連續存儲? – 2012-03-18 17:35:13

+0

@EmileCormier是的,元素是連續的。 – bames53 2012-03-18 17:38:11

+0

根據這個(http://stackoverflow.com/questions/8262963/stdarray-alignment),'std :: array'可以在數組元素之後留下填充。所以'std :: array '不保證是連續的。 – 2012-03-18 17:50:59