C++实现矩阵类(附代码和功能)_c++矩阵-程序员宅基地

技术标签: C++  矩阵  矩阵论    

       阅读这篇文章需要掌握C++类的知识以及线性代数的知识,如果有疑问,可在文章下方评论,作者会尽快回复;本文是在作者阅读了平冈和幸的程序员的数学3:线性代数之后而写,在代码设计上借鉴了书中的方法。

       希望这些代码能够帮助你更好地理解线性代数里提到的矩阵运算,笔者所写的矩阵运算代码,都是初学C++时实现的,并不具有工程应用的价值;真诚的希望读者能够使用更好的矩阵运算库,比如Eigen,OpenCV等,笔者对这两个C++库的理解也是比较深入的;当然,如果读者还了解Python的话,笔者建议学习numpy,numpy的Cpp代码可以在Github上搜索NumCpp。

        初写这份代码时,笔者才刚入C++,如今笔者将在github上上传新的矩阵运算代码NANAhttps://github.com/YuruTu/NANA 

相关文档见地址NANA doxygen生成文档https://yurutu.github.io/NANA/files.html

        具体实现的矩阵功能有: 

 

        最初版代码及其使用        

利用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;
}

求赞,求转发

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_37772174/article/details/83018940

智能推荐

从零开始搭建Hadoop_创建一个hadoop项目-程序员宅基地

文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目

心脏滴血漏洞HeartBleed CVE-2014-0160深入代码层面的分析_heartbleed代码分析-程序员宅基地

文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析

java读取ofd文档内容_ofd电子文档内容分析工具(分析文档、签章和证书)-程序员宅基地

文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat

基于FPGA的数据采集系统(一)_基于fpga的信息采集-程序员宅基地

文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集

微服务 spring cloud zuul com.netflix.zuul.exception.ZuulException GENERAL-程序员宅基地

文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception

邻接矩阵-建立图-程序员宅基地

文章浏览阅读358次。1.介绍图的相关概念  图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为:  G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图

随便推点

MDT2012部署系列之11 WDS安装与配置-程序员宅基地

文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc

python--xlrd/xlwt/xlutils_xlutils模块可以读xlsx吗-程序员宅基地

文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗

关于新版本selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘等问题_unresolved attribute reference 'find_element_by_id-程序员宅基地

文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver

DOM对象转换成jQuery对象转换与子页面获取父页面DOM对象-程序员宅基地

文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象

什么是算法?-程序员宅基地

文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法

【网络安全】网络安全的标准和规范_网络安全标准规范-程序员宅基地

文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范