矩阵计算(C++)

来源:互联网 发布:海康高清网络摄像机 编辑:程序博客网 时间:2024/04/30 08:47

#ifndef _MATRIX_H
#define _MATRIX_H

class Matrix
{
 private:
  int  row; // 矩阵的行数
  int  col; // 矩阵的列数
  int  n;  // 矩阵元素个数
  double* mtx; // 动态分配用来存放数组的空间
 public:
  Matrix(int row=1, int col=1);     // 带默认参数的构造函数
  Matrix(int row, int col, double mtx[]);   // 用数组创建一个矩阵
  Matrix(const Matrix &obj);      // copy构造函数
    ~Matrix() { delete[] this->mtx; }    

  void print()const;                        // 格式化输出矩阵
  int  getRow()const { return this->row; }  // 访问矩阵行数
  int  getCol()const { return this->col; }  // 访问矩阵列数
  int  getN()const   { return this->n;   }  // 访问矩阵元素个数
  double* getMtx()const { return this->mtx; }  // 获取该矩阵的数组
  
  // 用下标访问矩阵元素
  double  get(const int i, const int j)const;
  // 用下标修改矩阵元素值
  void  set(const int i, const int j, const double e);

  // 重载了一些常用操作符,包括 +,-,x,=,负号,正号,
  // A = B
  Matrix &operator= (const Matrix &obj);
  // +A
  Matrix  operator+ ()const { return *this; }
  // -A
  Matrix  operator- ()const;
  // A + B
  friend  Matrix  operator+ (const Matrix &A, const Matrix &B);
  // A - B
  friend  Matrix  operator- (const Matrix &A, const Matrix &B);
  // A * B 两矩阵相乘
  friend  Matrix  operator* (const Matrix &A, const Matrix &B);
  // a * B 实数与矩阵相乘
  friend  Matrix  operator* (const double &a, const Matrix &B);
  // A 的转置
  friend  Matrix  trv(const Matrix &A);
  // A 的行列式值,采用列主元消去法
  // 求行列式须将矩阵化为三角阵,此处为了防止修改原矩阵,采用传值调用
  friend  double  det(Matrix A);
  // A 的逆矩阵,采用高斯-若当列主元消去法
  friend  Matrix  inv(Matrix A);
};

#endif       

//===================================

 #include<iostream.h>                                                                              
#include<math.h>                                                                                  
#include<stdlib.h>                                                                                
#include<iomanip.h>                                                                               
#include"matrix.h"    
                                                                           
// 带默认参数值的构造函数                                                                         
// 构造一个row行col列的零矩阵                                                                     
Matrix::Matrix(int row, int col)                                                                  
{                                                                                                 
 this->row = row;    this->col = col;                                                        
 this->n   = row * col; this->mtx = new double[n];                                              
 for(int i=0; i<n; i++)                                                                          
  this->mtx[i] = 0.0;                                                                           
}  
                                                                                              
// 用一个数组初始化矩阵                                                                           
Matrix::Matrix(int row, int col, double mtx[])                                                    
{                                                                                                 
 this->row = row;    this->col = col;                                                        
 this->n   = row * col; this->mtx = new double[n];                                              
 for(int i=0; i<n; i++)                                                                          
  this->mtx[i] = mtx[i];                                                                        
}
                                                                                                 
// 拷贝构造函数,因为成员变量含有动态空间,防止传递参数                                           
// 等操作发生错误                                                                                 
Matrix::Matrix(const Matrix &obj)                                                                 
{                                                                                                 
 this->row = obj.getRow();                                                                       
 this->col = obj.getCol();                                                                       
 this->n   = obj.getN();                                                                         
 this->mtx = new double[n];                                                                      
 for(int i=0; i<n; i++)                                                                          
  this->mtx[i] = obj.getMtx()[i];                                                               
}                                                                                                 
                                                                                                  
// 格式化输出矩阵所有元素                                                                         
void Matrix::print()const                                                                         
{                                                                                                 
 for(int i=0; i<this->row; i++){                                                                 
  for(int j=0; j<this->col; j++)                                                                
   if(fabs(this->get(i,j)) <= 1.0e-10)                                                         
    cout << setiosflags(ios::left) << setw(12) << 0.0 << ' ';                                 
   else                                                                                        
    cout << setiosflags(ios::left) << setw(12) << this->get(i,j) << ' ';                      
  cout << endl;                                                                                 
 }                                                                                               
}                                                                                                 

// 获取矩阵元素
// 注意这里矩阵下标从(0,0)开始                                                                    
double Matrix::get(const int i, const int j)const                                                 
{                                                                                                 
 return this->mtx[i*this->col + j];                                                              
}

// 修改矩阵元素                                                                                   
void Matrix::set(const int i, const int j, const double e)                                        
{                                                                                                 
 this->mtx[i*this->col + j] = e;                                                                 
}                                                                                                 
                                                                                                  
// 重载赋值操作符,由于成员变量中含有动态分配                                                     
Matrix &Matrix::operator= (const Matrix &obj)                                                     
{                                                                                                 
 if(this == &obj)    // 将一个矩阵赋给它自己时简单做返回即可                                     
  return *this;                                                                                 
 delete[] this->mtx; // 首先删除目的操作数的动态空间                                             
 this->row = obj.getRow();                                                                       
 this->col = obj.getCol();                                                                       
 this->n   = obj.getN();                                                                         
 this->mtx = new double[n]; // 重新分配空间保存obj的数组                                         
 for(int i=0; i<n; i++)                                                                          
  this->mtx[i] = obj.getMtx()[i];                                                               
 return *this;                                                                                   
}  
                                                                                             
// 负号操作符,返回值为该矩阵的负矩阵,原矩阵不变                                                 
Matrix Matrix::operator- ()const                                                                  
{                                                                                                 
 // 为了不改变原来的矩阵,此处从新构造一个矩阵                                                   
 Matrix _A(this->row, this->col);                                                                
 for(int i=0; i<_A.n; i++)                                                                       
  _A.mtx[i] = -(this->mtx[i]);                                                                  
 return _A;                                                                                      
}
                                                                                                 
// 矩阵求和,对应位置元素相加                                                                     
Matrix operator+ (const Matrix &A, const Matrix &B)                                               
{                                                                                                 
 Matrix AB(A.row, A.col);                                                                        
 if(A.row!=B.row || A.col!=B.col){                                                               
  cout << "Can't do A+B/n"; // 如果矩阵A和B行列数不一致则不可相加                               
  exit(0);                                                                                      
 }                                                                                               
 for(int i=0; i<AB.n; i++)                                                                       
  AB.mtx[i] = A.mtx[i] + B.mtx[i];                                                              
 return AB;                                                                                      
}
                                                                                                 
// 矩阵减法,用加上一个负矩阵来实现                                                               
Matrix operator- (const Matrix &A, const Matrix &B)                                               
{                                                                                                 
 return (A + (-B));                                                                              
}
                                                                                                 
// 矩阵乘法                                                                                       
Matrix operator* (const Matrix &A, const Matrix &B)                                               
{                                                                                                 
 if(A.col != B.row){ // A的列数必须和B的行数一致                                                 
  cout << "Can't multiply/n";                                                                   
  exit(0);                                                                                     
 }                                                                                               
 Matrix AB(A.row, B.col); // AB用于保存乘积                                                      
 for(int i=0; i<AB.row; i++)                                                                     
 for(int j=0; j<AB.col; j++)                                                                     
 for(int k=0; k<A.col; k++)                                                                      
  AB.set(i, j, AB.get(i,j) + A.get(i,k)*B.get(k,j));                                            
 return AB;                                                                                      
}

// 矩阵与实数相乘
Matrix operator* (const double &a, const Matrix &B)
{
 Matrix aB(B);
 for(int i=0; i<aB.row; i++)
  for(int j=0; j<aB.col; j++)
   aB.set(i,j, a*B.get(i,j));
 
 return aB;
}

// 矩阵的转置 将(i,j)与(j,i)互换
// 此函数返回一个矩阵的转置矩阵,并不改变原来的矩阵
Matrix trv(const Matrix &A)
{
 Matrix AT(A.col, A.row);
 for(int i=0; i<AT.row; i++)
  for(int j=0; j<AT.col; j++)                                                                   
   AT.set(i, j, A.get(j,i));                                                                   
 return AT;                                                                                      
}
                                                                                 
// 矩阵行列式值,采用列主元消去法                                                                 
double det(Matrix A)                                                                              
{                                                                                                 
 if(A.row != A.col) {     // 矩阵必须为n*n的才可进行行列式求值                                    
  cout << "error" << endl;                                                                      
  return 0.0;       // 如果不满足行列数相等返回0.0                                          
 }                                                                                               
 double detValue = 1.0;     // 用于保存行列式值                                                     
 for(int i=0; i<A.getRow()-1; i++){  // 需要n-1步列化零操作                                       
  //------------------ 选主元 ---------------------------------                                 
  double max = fabs(A.get(i,i));  // 主元初始默认为右下方矩阵首个元素                            
  int    ind = i;      // 主元行号默认为右下方矩阵首行                                
                                                                                                  
  for(int j=i+1; j<A.getRow(); j++){ // 选择列主元                                              
   if(fabs(A.get(j,i)) > max){     // 遇到绝对值更大的元素                                    
    max = fabs(A.get(j,i));     // 更新主元值                                              
    ind = j;     // 更新主元行号                                            
   }                                                                                           
  }//loop j                                                                                     
  //------------------- 移动主元行 -----------------------------                                
  if(max <= 1.0e-10) return 0.0;   // 右下方矩阵首行为零,显然行列式值为零                   
  if(ind != i){       // 主元行非右下方矩阵首行                                 
   for(int k=i; k<A.getRow(); k++){  // 将主元行与右下方矩阵首行互换                           
    double temp = A.get(i,k);                                                                 
    A.set(i,k,A.get(ind,k));                                                                  
    A.set(ind,k,temp);                                                                        
   }                                                                                           
   detValue = -detValue;    // 互换行列式两行,行列式值反号                                        
  }                                                                                             
  //------------------- 消元 ----------------------------------                                 
  for(j=i+1; j<A.getRow(); j++){   // 遍历行                                                     
   double temp = A.get(j,i)/A.get(i,i);                                                        
                                                                                                  
   for(int k=i; k<A.getRow(); k++)  // 遍历行中每个元素,行首置0                                 
    A.set(j, k, A.get(j,k)-A.get(i,k)*temp);                                                  
  }                                                                                             
    detValue *= A.get(i,i);     // 每步消元都会产生一个对角线上元素,将其累乘                        
  }// loop i                                                                                      
  // 注意矩阵最后一个元素在消元的过程中没有被累乘到                                               
  return detValue * A.get(A.getRow()-1, A.getRow()-1);                                            
}//det()                                                                                          
                                                                                                  
// A的逆矩阵 高斯-若当消去法,按列选主元                                                          
Matrix inv(Matrix A)                                                                              
{                                                                                                 
 if(A.row != A.col){ // 只可求狭义逆矩阵,即行列数相同                                           
   cout << "Matrix should be N x N/n";                                                          
   exit(0);                                                                                     
 }                                                                                               
 // 构造一个与A行列相同的单位阵B                                                                 
 Matrix B(A.row,A.col);                                                                          
 for(int r=0; r<A.row; r++)                                                                      
  for(int c=0; c<A.col; c++)                                                                    
   if(r == c) B.set(r,c,1.0);                                                                  
                                                                                                  
 // 对矩阵A进行A.row次消元运算,每次保证第K列只有对角线上非零                                    
 // 同时以同样的操作施与矩阵B,结果A变为单位阵B为所求逆阵                                        
 for(int k=0; k<A.row; k++){                                                                     
 //------------------ 选主元 --------------------------------------                              
  double max = fabs(A.get(k,k));   // 主元初始默认为右下方矩阵首个元素                            
  int    ind = k;       // 主元行号默认为右下方矩阵首行                                
                                                // 结果第ind行为列主元行                                                                      
  for(int n=k+1; n<A.getRow(); n++){                                                            
   if(fabs(A.get(n,k)) > max){   // 遇到绝对值更大的元素                                    
    max = fabs(A.get(n,k));   // 更新主元值                                              
    ind = n;      // 更新主元行号                                            
   }                                                                                           
  }                                                                                             
  //------------------- 移动主元行 --------------------------------                             
  if(ind != k){       // 主元行不是右下方矩阵首行                                   
   for(int m=k; m<A.row; m++){   // 将主元行与右下方矩阵首行互换                               
    double tempa = A.get(k,m);                                                                
    A.set(k, m, A.get(ind,m));                                                                
    A.set(ind, m, tempa);                                                                     
   }                                                                                           
   for(m=0; m<B.row; m++){                                                                     
    double tempb = B.get(k,m);  // 对矩阵B施以相同操作                                        
    B.set(k, m, B.get(ind,m));  // B与A阶数相同,可在一个循环中                             
    B.set(ind, m, tempb);                                                                     
   }                                                                                           
  }                                                                                             
  //--------------------- 消元 -----------------------------------                              
  // 第k次消元操作,以第k行作为主元行,将其上下各行的第k列元素化为零                            
  // 同时以同样的参数对B施以同样的操作,此时可以将B看作A矩阵的一部分                            
   for(int i=0; i<A.col; i++){                                                                 
    if(i != k){                                                                               
     double Mik = -A.get(i,k)/A.get(k,k);                                                    
     for(int j=k+1; j<A.row; j++)                                                            
      A.set(i, j, A.get(i,j) + Mik*A.get(k,j));                                             
     for(j=0; j<B.row; j++)                                                                  
      B.set(i, j, B.get(i,j) + Mik*B.get(k,j));                                             
    }//end if                                                                                 
   }//loop i                                                                                   
                                                                                                  
   double Mkk = 1.0/A.get(k,k);                                                                
   for(int j=0; j<A.row; j++)                                                                  
    A.set(k, j, A.get(k,j) * Mkk);                                                            
   for(j=0; j<B.row; j++)                                                                      
    B.set(k, j, B.get(k,j) * Mkk);                                                            
 }//loop k                                                                                       
 return B;
}//inv()

原创粉丝点击