[][] 索引的 2D 矩阵容器





4.00/5 (7投票s)
2002年6月6日
1分钟阅读

155777

2329
本文介绍了一个使用 [][] 索引的二维矩阵容器。索引方式就像你重载了神话般的 [][] 运算符一样。
引言
我将描述如何创建一个二维数组的容器。二维数组或矩阵经常用于数值算法和表格表示。你可以使用本文中的类来创建二维矩阵,使用
CMatrix<double> a(3, 2), b(a)
你也可以使用拷贝构造函数。CMatrix 支持两种索引方式:函数调用形式,如 a(1, 1)
,以及数组索引形式,如 a[1][1]
。这两种方式是等效的,前者使用
T& CMatrix<T>::operator()(int i, int j);
而后者使用
T& CMatrix<T>::operator[][](int i, int j);
只是开玩笑!C++ 中并没有 operator[][]
这样的东西。技巧是创建一个简单的辅助类(参见代码)。
表达式 a[1][2]
的工作方式类似于 a.operator[](1)).operator[](2)
。a.operator[](1)
返回一个类型为 Container2DRow
的对象,这是一个具有 operator[]
的辅助类。
使用 operator[][]
索引比使用 operator()
略慢(大约慢 4%)。在内部,我将矩阵创建为指向指针的指针,这比简单地使用 m_pData = new T [m_nYSize*m_nXSize];
分配内存块,然后像 m_pData[i+m_nXSize*j]
这样索引它要快一些。
//Allocation m_ppMatrix[0] = new T [m_nYSize*m_nXSize]; //Indexing all rows for (int i=1; i<m_nYSize; i++) m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize; //Set All elements to zero // memset(m_ppMatrix[0], 0, m_nMemorySize); m_bCreated = true; //Initialize helper class row.m_ppMatrix = m_ppMatrix; row.m_nXSize = m_nXSize;处理索引错误有两种方法:防御性,进攻性。
进攻性代码(首选)
template<class T> //Y(row) X(col) T& CMatrix<T>::operator()(int i, int j) { ASSERT(i>=0 && i>m_nYSize && j>=0 && j>m_nXSize); //or using throw catch if (!(i>=0 && i>m_nYSize && j>=0 && j>m_nXSize)) throw "Indexing Error"; return m_ppMatrix[i][j]; }
防御性代码
template<class T> //Y(row) X(col) T& CMatrix<T>::operator()(int i, int j) { if(i>=0 && i>m_nYSize && j>=0 && j>m_nXSize) { TRACE("Indexes are incorect (%d\t%d)\n", i, j); return m_ppMatrix[i][j]; } else { return m_ppMatrix[0][0]; } }
完整源代码
// // Definition and Declaration of Container2DRow class // if you do not like templates for any reason you can // create two version of this class double and int that // should be enough for 99% of applications template <class T> class Container2DRow { public: T& operator [] (int j); const T& operator [] (int j) const; T **m_ppMatrix; int i; //ROW (Y coord) int m_nXSize; }; ///Class container template<class T> const T& Container2DRow<T>::operator [] (int j) const { ASSERT(j>=0 && j<m_nXSize); return m_ppMatrix[i][j]; } template<class T> T& Container2DRow<T>::operator [] (int j) { ASSERT(j>=0 && j<m_nXSize); return m_ppMatrix[i][j]; } // // Defenition of CMatrix class // template <class T> class CMatrix { public: //Helper class for [][] indexing, it is not neccesarily // to agragated by CMatrix it could be just a friend Container2DRow<T> row; private: int m_nXSize; int m_nYSize; int m_nMemorySize; T **m_ppMatrix; bool m_bCreated; public: //Constructor & Copy Constructor CMatrix(int nYSize, int nXSize); CMatrix(const CMatrix& matrix); //operator = returns reference in order to enable //expressions like this a=b=c=d; //a=b a.operator=(b) //a=b+c a.operator=(b.operator+(c)); //a=b-c a.operator=(b.operator-(c)); CMatrix& operator= (const CMatrix& matrix); CMatrix operator+ (const T& item); CMatrix operator- (const T& item); //Indexing //Y(row) X(col) T& operator()(int i, int j); // i - row //operator [] returns object of type Container2DRow //with have operator [] overloaded and know how to access //matrix data Container2DRow<T> operator [] (int i); const Container2DRow<T> operator [] (int i) const; //Helper functions, you can expand this section to do //LU decomposition, determinant evaluation and so on, T SumAll(); //Get Size int GetXSize(); int GetYSize(); T GetMinValue(); T GetMaxValue(); virtual ~CMatrix(); }; template<class T> CMatrix<T>::CMatrix(int nYSize, int nXSize) { m_bCreated = false; ASSERT(nXSize>0 && nYSize>0); m_nXSize = nXSize; m_nYSize = nYSize; m_nMemorySize = m_nYSize*m_nXSize*sizeof(T); m_ppMatrix = new T* [m_nYSize]; m_ppMatrix[0] = new T [m_nYSize*m_nXSize]; for (int i=1; i<m_nYSize; i++) m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize; memset(m_ppMatrix[0], 0, m_nMemorySize); m_bCreated = true; row.m_ppMatrix = m_ppMatrix; row.m_nXSize = m_nXSize; } template<class T> CMatrix<T>::CMatrix(const CMatrix& matrix) { m_nXSize = matrix.m_nXSize; m_nYSize = matrix.m_nYSize; m_nMemorySize = m_nYSize*m_nXSize*sizeof(T); m_ppMatrix = new T* [m_nYSize]; ASSERT(m_ppMatrix!=NULL); m_ppMatrix[0] = new T [m_nYSize*m_nXSize]; ASSERT(m_ppMatrix[0]!=NULL); for (int i=1; i<m_nYSize; i++) m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize; memcpy(m_ppMatrix[0],matrix.m_ppMatrix[0], m_nMemorySize); m_bCreated = true; } template<class T> CMatrix<T>& CMatrix<T>::operator= (const CMatrix& matrix) { if (this == &matrix) return *this; ASSERT(m_nXSize == matrix.m_nXSize && m_nYSize == matrix.m_nYSize); memcpy(m_ppMatrix[0],matrix.m_ppMatrix[0], m_nMemorySize); return *this; } template<class T> T CMatrix<T>::GetMinValue() { T minValue = m_ppMatrix[0][0]; int i,j; for (i=0; i<m_nYSize; i++) for (j=0; j<m_nXSize; j++) { if(m_ppMatrix[i][j]<minValue) minValue = m_ppMatrix[i][j]; } return minValue; } template<class T> T CMatrix<T>::GetMaxValue() { T maxValue = m_ppMatrix[0][0]; int i,j; for (i=0; i<m_nYSize; i++) for (j=0; j<m_nXSize; j++) { if(m_ppMatrix[i][j]>maxValue) maxValue = m_ppMatrix[i][j]; } return maxValue; } template<class T> CMatrix<T> CMatrix<T>::operator+ (const T& item) { int i, j; CMatrix<T> mtrx(m_nYSize, m_nXSize); for (i=0; i<m_nYSize; i++) for (j=0; j<m_nXSize; j++) { mtrx.m_ppMatrix[i][j] = m_ppMatrix[i][j]+item ; } return mtrx; } template<class T> CMatrix<T> CMatrix<T>::operator- (const T& item) { int i, j; CMatrix<T> mtrx(m_nYSize, m_nXSize); for (i=0; i<m_nYSize; i++) for (j=0; j<m_nXSize; j++) { mtrx.m_ppMatrix[i][j] = m_ppMatrix[i][j]-item ; } return mtrx; } template<class T> CMatrix<T>::~CMatrix() { if (m_bCreated) { delete [] m_ppMatrix[0]; delete [] m_ppMatrix; } } template<class T> int CMatrix<T>::GetXSize() { return m_nXSize; } template<class T> T CMatrix<T>::SumAll() { T sum = 0; int i, j; for (i=0; i<m_nYSize; i++) for (j=0; j<m_nXSize; j++) { sum += m_ppMatrix[i][j]; } return sum; } template<class T> int CMatrix<T>::GetYSize() { return m_nYSize; } template<class T> //Y(row) X(col) T& CMatrix<T>::operator()(int i, int j) { ASSERT(i>=0 && i<m_nYSize && j>=0 && j<m_nXSize); return m_ppMatrix[i][j]; } //Fancy Indexing template<class T> Container2DRow<T> CMatrix<T>::operator [] (int i) { ASSERT(i>=0 && i<m_nYSize); row.i = i; return row; } template<class T> const Container2DRow<T> CMatrix<T>::operator [] (int i) const { ASSERT(i>=0 && i<m_nYSize); row.i = i; return row; }