矩阵类对于学习C++的类有很大的帮助,如拷贝构造函数,算术符重载等。以下为设计矩阵类。
class MyMatrix
{
public:
int m_nRows; // 矩阵的行数
int m_nColumns; // 矩阵的列数
double* m_lpBuf; // 动态分配用来存放数组的空间
public:
MyMatrix();
MyMatrix(MyMatrix& A);
~MyMatrix();
}
由于矩阵的行和列都是不固定的,因而,需要将其设为动态分配内存的方式,分配函数如下:
MyMatrix::MyMatrix(int m, int n)//declare an mxn MyMatrix
{
m_nRows = m;
m_nColumns = n;
//需要防止乘法溢出,此处忽略之
this->m_lpBuf = new double[m*n];
memset(m_lpBuf,0,m*n*sizeof(double));
}
而析构函数则为:
~MyMatrix(){
m_nRows = 0;
m_nColumns =0;
if(m_lpBuf != NULL)
delete[] this->m_lpBuf;
};
一般的,对于有动态分配内存的类,均需要重写(深)拷贝构造函数,如下函数为深拷贝函数和赋值函数:
MyMatrix::MyMatrix(const MyMatrix& A) //copy ructor
{
this->m_nRows = A.m_nRows;
this->m_nColumns = A.m_nColumns;
if(m_nRows * m_nColumns != 0)
{
this->m_lpBuf = new double[m_nRows*m_nColumns];
for(int i = 0;i < (m_nRows*m_nColumns);++i)
this->m_lpBuf[i] = A.m_lpBuf[i];
}
else
m_lpBuf = NULL;
}
MyMatrix& MyMatrix::operator = ( const MyMatrix& A) //overloading =
{
if(this==&A)
return *this;
this->resize(A.m_nRows,A.m_nColumns);
for(int i=0;i<(m_nColumns*m_nRows);i++)
m_lpBuf[i] = A.m_lpBuf[i];
return *this;
}
对于经常使用Matlab的人,则会喜欢如下的表达方式:a(1,2),对于C++类,同样的可有:
double& MyMatrix::operator ()(int i, int j)
{
// Unsafe
return *(m_lpBuf + (i-1)*m_nColumns+(j-1));
}
对于重载操作符,可以这么写:
MyMatrix& MyMatrix::operator += ( MyMatrix& A)
{
if(!A.m_lpBuf) return *this;
if ( (this->m_nRows != A.m_nRows) || (this->m_nColumns != A.m_nColumns))
{
throw logic_error ("Size mismatch in MyMatrix addition");
}
for(int i=0;ithis->m_lpBuf[i]+=A.m_lpBuf[i];
return *this;
}
MyMatrix operator + (MyMatrix& A, MyMatrix& B)
{
MyMatrix tmp = A;
tmp+=B;
return tmp;
}
其它的如乘法操作可以依此来写。
对于将矩阵内的数据保存为txt文件和读取txt文件,可以如下编写:
bool MyMatrix::SaveToTxt(const char *filename)
{
ofstream file(filename,ios_base::out);
if(!file)
return false;
for(int i=1;i<=m_nColumns;++i)
{
for(int j=1;j<=m_nRows;++j)
file<20)<7)<1)*m_nColumns + (j-1));
file<<"\n"<return true;
}
bool MyMatrix::LoadFromTxt(const char *filename)
{
FILE *fp = NULL;
if(fopen_s(&fp,filename,"r")!=0)
return false;
int i = 0;
while(!feof(fp))
{
fscanf_s(fp,"%lf",(m_lpBuf+i));
if(++i>m_nRows*m_nColumns)
break;
}
fclose(fp);
return true;
}
以下程序对矩阵求逆,其方法即为算术中的计算方法
MyMatrix inv(MyMatrix& A)
{
int rows = A.m_nRows;
MyMatrix C(rows,rows);
if(A.m_nRows != A.m_nColumns)
return C;
// 构造一个与A行相同的单位阵B = |A : E|
MyMatrix B(rows, rows*2, 0);
for(int i = 1;i<=rows;++i)
for(int j=1;j<=rows;++j)
B(i,j) = A(i,j);
for(int i = 1;i<=rows;++i)
B(i,i+rows) = 1;
double tempa = 0;
// 对矩阵A进行B.row次消元运算,每次保证第K列只有对角线上非零
for(int k=1; k<=B.m_nRows; k++)
{
//------------------ 选主元 --------------------------------
double max = fabs(B(k,k)); // 主元初始默认为右下方矩阵首个元素
int ind = k; // 主元行号默认为右下方矩阵首行
// 结果第ind行为列主元行
for(int n=k+1; n<=B.m_nRows; ++n)
{
if(fabs(B(n,k)) > max)
{
// 遇到绝对值更大的元素
max = fabs(B(n,k)); // 更新主元值
ind = n; // 更新主元行号
}
}
//------------------- 移动主元行 -------------------------
if(ind != k)
{ // 主元行不是右下方矩阵首行
for(int m=k; m<=rows*2; ++m)
{ // 将主元行与右下方矩阵首行互换
tempa = B(k,m);
B(k,m) = B(ind, m);
B(ind,m) = tempa;
}
}
//--------------------- 消元 --------------------------------
// 第k次消元操作,以第k行作为主元行,将其上下各行的第k列元素化为零
// 同时以同样的参数对B施以同样的操作,此时可以将B看作A矩阵的一部分
tempa = 1.0/B(k,k);
for(int i=k; i<=rows*2; ++i)
{
B(k,i) *= tempa;
}
for(int i=1; i<=rows; i++)
{
if(i != k)
{
tempa = -B(i,k);
for(int j=k; j<=B.m_nColumns; ++j)
B(i,j) += tempa*B(k,j);
}//end if
}//loop i
}//loop k
for(int i = 1;i<=rows;++i)
for(int j = 1;j<=rows;++j)
C(i,j) = B(i,j+rows);
return C;
}//inv()