C++實現矩陣類(附代碼和功能)

 

       閱讀這篇文章需要掌握C++類的知識以及線性代數的知識,如果有疑問,可在文章下方評論,作者會盡快回復;本文是在作者閱讀了平岡和幸的程序員的數學3:線性代數之後而寫,在代碼設計上借鑑了書中的方法;該書所提供的代碼爲Ruby代碼,本文代碼爲原創代碼。

       希望這些代碼能夠幫助你更好地理解線性代數裏提到的矩陣運算

這裏提供的代碼也許不是最新的,想要獲得最新更新,可訪問我的github空間https://github.com/YuruTu/Matrix

利用C++的類實現矩陣的運算,可實現矩陣的+-*運算,以及用高斯消去法求解線性方程組Ax=b

2018/10/13新增功能 矩陣的行列變換 高斯消元法得到上三角矩陣 

2018/12/9實現矩陣的逆運算等

預編譯頭文件

pch.h

#ifndef PCH_H
#define PCH_H
#include <cmath>
#include <iostream>
#include <stdlib.h>
#include <cmath>
// TODO: 添加要在此處預編譯的標頭

#endif //PCH_H

 頭文件.h

/*
author: cclplus
date:2018/12/09
if you think it is necessary to reward me,
my alipay account number is [email protected]
*/

#ifndef __MATRIX_CLL_H__
#define __MATRIX_CCL_H__
#include "pch.h"
 
class Matrix {
private:
	int rows_num, cols_num;
	double **p;
	void initialize();//初始化矩陣
 
public:
	Matrix(int, int);
	Matrix(int, int, double);//預配分空間
	virtual ~Matrix();//析構函數應當是虛函數,除非此類不用做基類
	Matrix& operator=(const Matrix&);//矩陣的複製
	Matrix& operator=(double *);//將數組的值傳給矩陣
	Matrix& operator+=(const Matrix&);//矩陣的+=操作
	Matrix& operator-=(const Matrix&);//-=
	Matrix& operator*=(const Matrix&);//*=
	Matrix operator*(const Matrix & m)const;
	static Matrix Solve(const Matrix&, const Matrix&);//求解線性方程組Ax=b
	void Show() const;//矩陣顯示
	void swapRows(int, int);
	double det();//求矩陣的行列式
	double Point(int i, int j) const;
	static Matrix inv(Matrix);//求矩陣的逆矩陣
	static Matrix eye(int );//製造一個單位矩陣
	int row() const;
	int col() const;
	static Matrix T(const Matrix & m);//矩陣轉置的實現,且不改變矩陣
	Matrix gaussianEliminate();//高斯消元法
	friend std::istream& operator>>(std::istream&, Matrix&);//實現矩陣的輸入
};


#endif

頭文件.cpp

/*
author: cclplus
date : 2018 / 12 / 09
if you think it is necessary to reward me,
my alipay account number is [email protected]
*/
#include "pch.h"
#include "matrix.h"
using std::endl;
using std::cout;
using std::istream;
const double EPS = 1e-10;
void Matrix::initialize() {//初始化矩陣大小
	p = new double*[rows_num];//分配rows_num個指針
	for (int i = 0; i < rows_num; ++i) {
		p[i] = new double[cols_num];//爲p[i]進行動態內存分配,大小爲cols
	}
}
//聲明一個全0矩陣
Matrix::Matrix(int rows, int cols)
{
	rows_num = rows;
	cols_num = cols;
	initialize();
	for (int i = 0; i < rows_num; i++) {
		for (int j = 0; j < cols_num; j++) {
			p[i][j] = 0;
		}
	}
}
//聲明一個值全部爲value的矩陣
Matrix::Matrix(int rows, int cols, double value)
{
	rows_num = rows;
	cols_num = cols;
	initialize();
	for (int i = 0; i < rows_num; i++) {
		for (int j = 0; j < cols_num; j++) {
			p[i][j] = value;
		}
	}
}
 
//析構函數
Matrix::~Matrix() {
 for (int i = 0; i < rows_num; ++i) {
			delete[] p[i];
		}
		delete[] p;
}
//實現矩陣的複製
Matrix& Matrix::operator=(const Matrix& m)
{
	if (this == &m) {
		return *this;
	}
 
	if (rows_num != m.rows_num || cols_num != m.cols_num) {
		for (int i = 0; i < rows_num; ++i) {
			delete[] p[i];
		}
		delete[] p;
 
		rows_num = m.rows_num;
		cols_num = m.cols_num;
		initialize();
	}
 
	for (int i = 0; i < rows_num; i++) {
		for (int j = 0; j < cols_num; j++) {
			p[i][j] = m.p[i][j];
		}
	}
	return *this;
}
//將數組的值傳遞給矩陣(要求矩陣的大小已經被聲明過了)
Matrix& Matrix::operator=(double *a){
	for(int i=0;i<rows_num;i++){
		for(int j=0;j<cols_num;j++){
			p[i][j]= *(a+i*cols_num+j);
		}
	}
	return *this;
}
//+=操作
Matrix& Matrix::operator+=(const Matrix& m)
{
	for (int i = 0; i < rows_num; i++) {
		for (int j = 0; j < cols_num; j++) {
			p[i][j] += m.p[i][j];
		}
	}
	return *this;
}
//實現-=
Matrix& Matrix::operator-=(const Matrix& m)
{
	for (int i = 0; i < rows_num; i++) {
		for (int j = 0; j < cols_num; j++) {
			p[i][j] -= m.p[i][j];
		}
	}
	return *this;
}
//實現*=
Matrix& Matrix::operator*=(const Matrix& m)
{
	Matrix temp(rows_num, m.cols_num);//若C=AB,則矩陣C的行數等於矩陣A的行數,C的列數等於B的列數。
	for (int i = 0; i < temp.rows_num; i++) {
		for (int j = 0; j < temp.cols_num; j++) {
			for (int k = 0; k < cols_num; k++) {
				temp.p[i][j] += (p[i][k] * m.p[k][j]);
			}
		}
	}
	*this = temp;
	return *this;
}
//實現矩陣的乘法
Matrix Matrix::operator*(const Matrix & m)const{
	Matrix ba_M(rows_num,m.cols_num,0.0);
	for(int i=0;i<rows_num;i++){
		for(int j=0;j<m.cols_num;j++){
			for(int k=0;k<cols_num;k++){
				ba_M.p[i][j]+=(p[i][k]*m.p[k][j]);
			}
		}
	}
	return ba_M;
}

//解方程Ax=b
Matrix Matrix::Solve(const Matrix &A, const Matrix &b)
{
	//高斯消去法實現Ax=b的方程求解
	for (int i = 0; i < A.rows_num; i++) {
		if (A.p[i][i] == 0) {
 
			cout << "請重新輸入" << endl;
		}
		for (int j = i + 1; j < A.rows_num; j++) {
			for (int k = i + 1; k < A.cols_num; k++) {
				A.p[j][k] -= A.p[i][k] * (A.p[j][i] / A.p[i][i]);
				if (abs(A.p[j][k]) < EPS)
					A.p[j][k] = 0;
			}
			b.p[j][0] -= b.p[i][0] * (A.p[j][i] / A.p[i][i]);
			if (abs(A.p[j][0]) < EPS)
				A.p[j][0] = 0;
			A.p[j][i] = 0;
		}
	}
 
	// 反向代換
	Matrix x(b.rows_num, 1);
	x.p[x.rows_num - 1][0] = b.p[x.rows_num - 1][0] / A.p[x.rows_num - 1][x.rows_num - 1];
	if (abs(x.p[x.rows_num - 1][0]) < EPS)
		x.p[x.rows_num - 1][0] = 0;
	for (int i = x.rows_num - 2; i >= 0; i--) {
		double sum = 0;
		for (int j = i + 1; j < x.rows_num; j++) {
			sum += A.p[i][j] * x.p[j][0];
		}
		x.p[i][0] = (b.p[i][0] - sum) / A.p[i][i];
		if (abs(x.p[i][0]) < EPS)
			x.p[i][0] = 0;
	}
 
	return x;
}
 
//矩陣顯示
void Matrix::Show() const {
	//cout << rows_num <<" "<<cols_num<< endl;//顯示矩陣的行數和列數
	for (int i = 0; i < rows_num; i++) {
		for (int j = 0; j < cols_num; j++) {
			cout << p[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}
//實現行變換
void Matrix::swapRows(int a, int b)
{
	a--;
	b--;
	double *temp = p[a];
	p[a] = p[b];
	p[b] = temp;
}
//計算矩陣行列式的值
double Matrix::det(){
	//爲計算行列式做一個備份
	double ** back_up;
	back_up=new double *[rows_num];
	for(int i=0;i<rows_num;i++){
		back_up[i]=new double[cols_num];
	}
	for(int i=0;i<rows_num;i++){
		for(int j=0;j<cols_num;j++){
			back_up[i][j]=p[i][j];
		}
	}
	if(rows_num!=cols_num){
		std::abort();//只有方陣才能計算行列式,否則調用中斷強制停止程序
	}
	double ans=1;
	for(int i=0;i<rows_num;i++){
		//通過行變化的形式,使得矩陣對角線上的主元素不爲0
		if(abs(p[i][i])<=EPS){
			bool flag=false;
			for(int j=0;(j<cols_num)&&(!flag);j++){
			//若矩陣的一個對角線上的元素接近於0且能夠通過行變換使得矩陣對角線上的元素不爲0
				if((abs(p[i][j])>EPS)&&(abs(p[j][i])>EPS)){
					flag=true;
					//注:進行互換後,p[i][j]變爲p[j][j],p[j][i]變爲p[i][i]
					//對矩陣進行行變換
					double temp;
					for(int k=0;k<cols_num;k++){
						temp=p[i][k];
						p[i][k]=p[j][k];
						p[j][k]=temp;
					}
				}
			}
		if(flag)
			return 0;
		}
	}
	for(int i=0;i<rows_num;i++){
		for(int j=i+1;j<rows_num;j++){
			for(int k=i+1;k<cols_num;k++){
				p[j][k]-=p[i][k]*(p[j][i]*p[i][i]);
			}
		}
	}
	for(int i=0;i<rows_num;i++){
		ans*=p[i][i];
	}
	for(int i=0;i<rows_num;i++){
		for(int j=0;j<cols_num;j++){
			p[i][j]=back_up[i][j];
		}
	}
	return ans;
}
//返回矩陣第i行第j列的數
double Matrix::Point(int i, int j) const{
	return this->p[i][j];
}
//求矩陣的逆矩陣
Matrix Matrix::inv(Matrix A){
	if(A.rows_num!=A.cols_num){
		std::cout<<"只有方陣能求逆矩陣"<<std::endl;
		std::abort();//只有方陣能求逆矩陣
	}
	double temp;
	Matrix A_B=Matrix(A.rows_num,A.cols_num);
	A_B=A;//爲矩陣A做一個備份
	Matrix B=eye(A.rows_num);
	//將小於EPS的數全部置0
	for (int i = 0; i < A.rows_num; i++) {
		for (int j = 0; j < A.cols_num; j++) {
			if (abs(A.p[i][j]) <= EPS) {
				A.p[i][j] = 0;
			}
		}
	}
	//選擇需要互換的兩行選主元
	for(int i=0;i<A.rows_num;i++){
		if(abs(A.p[i][i])<=EPS){
			bool flag=false;
			for(int j=0;(j<A.rows_num)&&(!flag);j++){
				if((abs(A.p[i][j])>EPS)&&(abs(A.p[j][i])>EPS)){
					flag=true;
					for(int k=0;k<A.cols_num;k++){
						temp=A.p[i][k];
						A.p[i][k]=A.p[j][k];
						A.p[j][k]=temp;
						temp=B.p[i][k];
						B.p[i][k]=B.p[j][k];
						B.p[j][k]=temp;
					}
				}
			}
			if(!flag){
				std::cout<<"逆矩陣不存在\n";
				std::abort();
			}
		}
	}
	//通過初等行變換將A變爲上三角矩陣
	double temp_rate;
	for(int i=0;i<A.rows_num;i++){
		for(int j=i+1;j<A.rows_num;j++){
			temp_rate=A.p[j][i]/A.p[i][i];
			for(int k=0;k<A.cols_num;k++){
				A.p[j][k]-=A.p[i][k]*temp_rate;
				B.p[j][k]-=B.p[i][k]*temp_rate;
			}
			A.p[j][i]=0;
		}
	}
	//使對角元素均爲1
	for(int i=0;i<A.rows_num;i++){
		temp=A.p[i][i];
		for(int j=0;j<A.cols_num;j++){
			A.p[i][j]/=temp;
			B.p[i][j]/=temp;
		}
	}
	//std::cout<<"算法可靠性檢測,若可靠,輸出上三角矩陣"<<std::endl;
	//將已經變爲上三角矩陣的A,變爲單位矩陣
	for(int i=A.rows_num-1;i>=1;i--){
		for(int j=i-1;j>=0;j--){
			temp=A.p[j][i];
			for(int k=0;k<A.cols_num;k++){
				A.p[j][k]-=A.p[i][k]*temp;
				B.p[j][k]-=B.p[i][k]*temp;
			}
		}
	}
	std::cout<<"算法可靠性檢測,若可靠,輸出單位矩陣"<<std::endl;
	for(int i=0;i<A.rows_num;i++){
		for(int j=0;j<A.cols_num;j++){
			printf("%7.4lf\t\t",A.p[i][j]);
		}
		cout << endl;
	}
	A=A_B;//還原A
	return B;//返回該矩陣的逆矩陣
}
//製造一個單位矩陣
Matrix Matrix::eye(int n){
	Matrix A(n,n);
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(i==j){
				A.p[i][j]=1;
			}else{
				A.p[i][j]=0;
			}
		}
	}
	return A;
}
//讀取矩陣行列數
int Matrix::row() const{
	return rows_num;
}
int Matrix::col() const{
	return cols_num;
}
//實現矩陣的轉置
Matrix Matrix::T(const Matrix & m)
{	int col_size=m.col();
	int row_size=m.row();
	Matrix mt(col_size, row_size);
	for (int i = 0; i <row_size; i++) {
		for (int j = 0; j <col_size; j++) {
			mt.p[j][i] = m.p[i][j];
		}
	}
	return mt;
}
//高斯消元法
Matrix Matrix::gaussianEliminate()
{
	Matrix Ab(*this);
	int rows = Ab.rows_num;
	int cols = Ab.cols_num;
	int Acols = cols - 1;
 
	int i = 0; //跟蹤行
	int j = 0; //跟蹤列
	while (i < rows)
	{
		bool flag = false;
		while (j < Acols && !flag)
		{
			if (Ab.p[i][j] != 0) {
				flag = true;
			}
			else {
				int max_row = i;
				double max_val = 0;
				for (int k = i + 1; k < rows; ++k)
				{
					double cur_abs = Ab.p[k][j] >= 0 ? Ab.p[k][j] : -1 * Ab.p[k][j];
					if (cur_abs > max_val)
					{
						max_row = k;
						max_val = cur_abs;
					}
				}
				if (max_row != i) {
					Ab.swapRows(max_row, i);
					flag = true;
				}
				else {
					j++;
				}
			}
		}
		if (flag)
		{
			for (int t = i + 1; t < rows; t++) {
				for (int s = j + 1; s < cols; s++) {
					Ab.p[t][s] = Ab.p[t][s] - Ab.p[i][s] * (Ab.p[t][j] / Ab.p[i][j]);
					if (abs(Ab.p[t][s]) <EPS)
						Ab.p[t][s] = 0;
				}
				Ab.p[t][j] = 0;
			}
		}
		i++;
		j++;
	}
	return Ab;
}
//實現矩陣的輸入
istream& operator>>(istream& is, Matrix& m)
{
	for (int i = 0; i < m.rows_num; i++) {
		for (int j = 0; j < m.cols_num; j++) {
			is >> m.p[i][j];
		}
	}
	return is;
}

主程序



#include "matrix.h"
using namespace std;

int main()
{
	Matrix A = Matrix(3, 3);
	cin >> A;
	Matrix b = Matrix(3, 1);
	cin >> b;
	Matrix x = Matrix::Solve(A, b);
	x.Show();
	return 0;
}

運行結果

新功能使用方法

 A.gaussianEliminate();//將A通過高斯消元法後得到上三角矩陣,保存爲A

A.swapRows(3, 1);//轉換矩陣A的第三行和第一行

       CSDN上展示的類庫並非是最新的,此本版較老,建議訪問我的coding網頁下載最新版矩陣類庫使用。除了矩陣運算外,我還會再上面添加一些數值分析算法,目前已添加的有迭代法解線性代數方程Ax = b。

網址https://dev.tencent.com/u/cclplus/NA

求贊,求轉發

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章