マトリックスをどのように動的に割り当てますか?
-
05-07-2019 - |
質問
C ++で2Dマトリックスを動的に割り当てる方法 私はすでに知っていることに基づいて試しました:
#include <iostream>
int main(){
int rows;
int cols;
int * arr;
arr = new int[rows][cols];
}
1つのパラメーターに対して機能しますが、現在は2つに対して機能します。どうすればよいですか
解決
マトリックスは、実際には配列の配列です。
int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
もちろん、マトリックスを削除するには、次の手順を実行する必要があります。
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
delete [] matrix;
別の可能性を見つけたところです:
int rows = ..., cols = ...;
int** matrix = new int*[rows];
if (rows)
{
matrix[0] = new int[rows * cols];
for (int i = 1; i < rows; ++i)
matrix[i] = matrix[0] + i * cols;
}
この配列の解放は簡単です:
if (rows) delete [] matrix[0];
delete [] matrix;
このソリューションには、いくつかの小さなチャンクではなく、すべての要素に単一の大きなメモリブロックを割り当てるという利点があります。ただし、私が最初に投稿した解決策は、配列の配列の概念のより良い例です。
他のヒント
これを実現するためにstd::vectors
を使用することもできます:
std::vector< std::vector<int> >
例:
std::vector< std::vector<int> > a;
//m * n is the size of the matrix
int m = 2, n = 4;
//Grow rows by m
a.resize(m);
for(int i = 0 ; i < m ; ++i)
{
//Grow Columns by n
a[i].resize(n);
}
//Now you have matrix m*n with default values
//you can use the Matrix, now
a[1][0]=1;
a[1][1]=2;
a[1][2]=3;
a[1][3]=4;
//OR
for(i = 0 ; i < m ; ++i)
{
for(int j = 0 ; j < n ; ++j)
{ //modify matrix
int x = a[i][j];
}
}
#include <boost/multi_array.hpp>
int main(){
int rows;
int cols;
boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
#include <iostream>
int main(){
int rows=4;
int cols=4;
int **arr;
arr = new int*[rows];
for(int i=0;i<rows;i++){
arr[i]=new int[cols];
}
// statements
for(int i=0;i<rows;i++){
delete []arr[i];
}
delete []arr;
return 0;
}
arr = new int[cols*rows];
構文を気にしない場合
arr[row * cols + col] = Aij;
またはoperator []を使用して、どこかにオーバーロードします。これは、配列の配列よりもキャッシュに優しい場合もあれば、そうでない場合もあります。おそらく気にする必要はないでしょう。私は、a)配列の配列は解決策であるだけでなく、b)行列がメモリの1つのブロックにある場合、いくつかの操作の実装がより簡単になることを指摘したいだけです。例:
for(int i=0;i < rows*cols;++i)
matrix[i]=someOtherMatrix[i];
1行より短い
for(int r=0;i < rows;++r)
for(int c=0;i < cols;++s)
matrix[r][c]=someOtherMatrix[r][c];
このようなマトリックスに行を追加するのはより苦痛ですが
または1D配列を割り当てるだけで、2D形式で要素を参照できます:
行2、列3のアドレス(左上隅は行0、列0):
arr [2 * MATRIX_WIDTH + 3]
ここでMATRIX_WIDTHは行の要素数です。
配列の配列を記述する他の答えは正しいです。
しかし、配列で数学的なことをする予定がある場合、またはスパース行列のような特別なものが必要な場合は、 TNT を使用して車輪を再発明しすぎる
数学的な演算子を必要としない場合、単純なマトリックスとして使用できるこのグリッドクラスがあります。
/**
* Represents a grid of values.
* Indices are zero-based.
*/
template<class T>
class GenericGrid
{
public:
GenericGrid(size_t numRows, size_t numColumns);
GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue);
const T & get(size_t row, size_t col) const;
T & get(size_t row, size_t col);
void set(size_t row, size_t col, const T & inT);
size_t numRows() const;
size_t numColumns() const;
private:
size_t mNumRows;
size_t mNumColumns;
std::vector<T> mData;
};
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns);
}
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns, inInitialValue);
}
template<class T>
const T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx) const
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx)
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
void GenericGrid<T>::set(size_t rowIdx, size_t colIdx, const T & inT)
{
mData[rowIdx*mNumColumns + colIdx] = inT;
}
template<class T>
size_t GenericGrid<T>::numRows() const
{
return mNumRows;
}
template<class T>
size_t GenericGrid<T>::numColumns() const
{
return mNumColumns;
}
ダブルポインターを使用することは、実行速度/最適化と読みやすさの妥協点として最適です。単一の配列を使用してマトリックスのコンテンツを保存することは、実際にはダブルポインターが行うことです。
次のテンプレートクリエーター関数を正常に使用しました(はい、古いCスタイルのポインター参照を使用していることは知っていますが、パラメーターの変更に関して呼び出し側でコードがより明確になります-ポインターについて好きなことは参照では不可能です。意味がわかります):
///
/// Matrix Allocator Utility
/// @param pppArray Pointer to the double-pointer where the matrix should be allocated.
/// @param iRows Number of rows.
/// @param iColumns Number of columns.
/// @return Successful allocation returns true, else false.
template <typename T>
bool NewMatrix(T*** pppArray,
size_t iRows,
size_t iColumns)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{ // I prefer using the shorter 0 in stead of NULL.
if (!((*pppArray) != 0)) // Test if the first element is currently unassigned.
{ // The "double-not" evaluates a little quicker in general.
// Allocate and assign pointer array.
(*pppArray) = new T* [iRows];
if ((*pppArray) != 0) // Test if pointer-array allocation was successful.
{
// Allocate and assign common data storage array.
(*pppArray)[0] = new T [iRows * iColumns];
if ((*pppArray)[0] != 0) // Test if data array allocation was successful.
{
// Using pointer arithmetic requires the least overhead. There is no
// expensive repeated multiplication involved and very little additional
// memory is used for temporary variables.
T** l_ppRow = (*pppArray);
T* l_pRowFirstElement = l_ppRow[0];
for (size_t l_iRow = 1; l_iRow < iRows; l_iRow++)
{
l_ppRow++;
l_pRowFirstElement += iColumns;
l_ppRow[0] = l_pRowFirstElement;
}
l_bResult = true;
}
}
}
}
}
上記のユーティリティを使用して作成されたメモリの割り当てを解除するには、単に逆に割り当てを解除する必要があります。
///
/// Matrix De-Allocator Utility
/// @param pppArray Pointer to the double-pointer where the matrix should be de-allocated.
/// @return Successful de-allocation returns true, else false.
template <typename T>
bool DeleteMatrix(T*** pppArray)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{
if ((*pppArray) != 0) // Test if pointer array was assigned.
{
if ((*pppArray)[0] != 0) // Test if data array was assigned.
{
// De-allocate common storage array.
delete [] (*pppArray)[0];
}
}
// De-allocate pointer array.
delete [] (*pppArray);
(*pppArray) = 0;
l_bResult = true;
}
}
}
これらの上記のテンプレート関数を使用するのは非常に簡単です(例):
.
.
.
double l_ppMatrix = 0;
NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
.
.
.
DeleteMatrix(&l_ppMatrix);
const int nRows = 20;
const int nCols = 10;
int (*name)[nCols] = new int[nRows][nCols];
std::memset(name, 0, sizeof(int) * nRows * nCols); //row major contiguous memory
name[0][0] = 1; //first element
name[nRows-1][nCols-1] = 1; //last element
delete[] name;
最も明確な<!> amp; C ++で動的な2D配列を割り当てる直感的な方法。この例のテンプレートは、すべてのケースを対象としています。
template<typename T> T** matrixAllocate(int rows, int cols, T **M)
{
M = new T*[rows];
for (int i = 0; i < rows; i++){
M[i] = new T[cols];
}
return M;
}
...
int main()
{
...
int** M1 = matrixAllocate<int>(rows, cols, M1);
double** M2 = matrixAllocate(rows, cols, M2);
...
}