c++ - resueltos - matrices en programacion
¿Cómo asignas dinámicamente una matriz? (11)
¿Cómo asignas dinámicamente una matriz 2D en C ++? Lo he intentado en base a lo que ya sé:
#include <iostream>
int main(){
int rows;
int cols;
int * arr;
arr = new int[rows][cols];
}
Funciona para un parámetro, pero ahora para dos. ¿Qué tengo que hacer?
El uso del doble puntero es, con mucho, el mejor compromiso entre la velocidad de ejecución / optimización y la legibilidad. Usar una matriz única para almacenar el contenido de la matriz es en realidad lo que hace un puntero doble.
He utilizado con éxito la siguiente función de creador de plantilla (sí, sé que uso referencias de punteros de estilo C anteriores, pero hace que el código sea más claro en el lado de la llamada con respecto al cambio de parámetros, algo que me gusta de los punteros que no es posible con Referencias. Verás lo que quiero decir):
///
/// 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;
}
}
}
}
}
Para desasignar la memoria creada usando la utilidad mencionada anteriormente, uno simplemente tiene que desasignar a la inversa.
///
/// 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;
}
}
}
Para usar estas funciones de plantilla mencionadas anteriormente es muy fácil (por ejemplo):
.
.
.
double l_ppMatrix = 0;
NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
.
.
.
DeleteMatrix(&l_ppMatrix);
Esta es la forma más clara e intuitiva que conozco para asignar una matriz dinámica en 2D a C ++. La plantilla en este ejemplo cubre todos los casos.
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);
...
}
La otra respuesta que describe matrices de matrices es correcta.
PERO si está planeando hacer algo matemático con los arreglos, o si necesita algo especial como matrices dispersas, debería mirar una de las muchas librerías de matemáticas como TNT antes de reinventar muchas ruedas.
Prueba boost::multi_array
#include <boost/multi_array.hpp>
int main(){
int rows;
int cols;
boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
También puedes usar std::vectors
para lograr esto:
utilizando std::vector< std::vector<int> >
Ejemplo:
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];
}
}
Tengo esta clase de cuadrícula que se puede usar como una matriz simple si no necesita operadores matemáticos.
/**
* 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;
}
Una matriz es en realidad una matriz de matrices.
int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
Por supuesto, para borrar la matriz, debes hacer lo siguiente:
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
delete [] matrix;
Acabo de descubrir otra posibilidad:
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;
}
Liberar esta matriz es más fácil:
if (rows) delete [] matrix[0];
delete [] matrix;
Esta solución tiene la ventaja de asignar un solo bloque grande de memoria para todos los elementos, en lugar de varios trozos pequeños. Sin embargo, la primera solución que publiqué es un ejemplo mejor del concepto de arrays de arrays .
o simplemente puede asignar una matriz 1D pero elementos de referencia de una manera 2D:
para abordar la fila 2, columna 3 (la esquina superior izquierda es la fila 0, columna 0):
arr [2 * MATRIX_WIDTH + 3]
donde MATRIX_WIDTH es el número de elementos en una fila.
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;
#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];
Si a ti tampoco te importa la sintaxis
arr[row * cols + col] = Aij;
o use el operador [] overaloading en alguna parte. Esto puede ser más fácil de almacenar en caché que una matriz de matrices, o puede que no, más probablemente no debería preocuparse por ello. Solo quiero señalar que a) la matriz de arreglos no es solo una solución, b) algunas operaciones son más fáciles de implementar si la matriz se encuentra en un bloque de memoria. P.ej
for(int i=0;i < rows*cols;++i)
matrix[i]=someOtherMatrix[i];
una línea más corta que
for(int r=0;i < rows;++r)
for(int c=0;i < cols;++s)
matrix[r][c]=someOtherMatrix[r][c];
aunque agregar filas a tal matriz es más doloroso