65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (7投票s)

2002年6月6日

1分钟阅读

viewsIcon

155777

downloadIcon

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;
}
© . All rights reserved.