#C++矩阵类的实现

C++矩阵类的实现

环境:Win10、VS2017

最近老师布置一个简单的C++作业——实现一个矩阵类,并且实现矩阵运算。
主要实现运算为矩阵的加、减、乘、除以及求行列式,伴随矩阵,代数余子式和逆矩阵等。在参考网上的一些前辈的代码后,写出了这些运算的简单实现。
因为矩阵的加、减、乘、除(完成求逆矩阵后)、转置等运算比较简单,所以此处主要讲上述其余运算的实现。

话不多说,开始:
首先定义一个矩阵类,需要实现功能略多,还有各运算函数的声明,大概如下:

class Matrix 
{
publicMatrix(): DataArray(0) {}
	Matrix(int rows, int cols) :DataArray(rows)
	{
		for (int i = 0; i < rows; i++)
			DataArray[i].resize(cols);
	}
	Matrix(const Matrix &m) { (*this) = m; }
	friend istream&operator>>(istream &is, Matrix &A);         //重载运算符>>用于输入矩阵
	friend ostream&operator<<(ostream &os, const Matrix &A);  //重载运算符<<用于输出矩阵
	//加、减、乘
	const Matrix& operator+=(const Matrix &A); 
	.........
	//需要用到一些的函数
	void resize(int, int);                //改变矩阵大小
	bool push_back(const vector<T>& v) { DataArray.push_back(v); }     //添加一行
	void swap_row(int ,int );                       //交换矩阵的两行
	int rows() const { return DataArray.size(); } 
	int cols() const { return rows() ? (DataArray[0].size()) : 0; }
	bool empty() const { return rows() == 0; }
	bool square() const { return !(empty()) && rows() == cols(); }       //判断矩阵是否为方阵
	const vector<double> operator[](int row) const { return DataArray[row]; }  //这两行用于取矩阵元素
	vector<double>& operator[](int row) { return DataArray[row]; }
protected:
	vector<vector<double>>DataArray;
};

const double det(const Matrix &A); //求行列式
const double alge_cofactor(const Matrix &A, int row, int col);//求代数余子式
const Matrix adjoint(const Matrix &A); //求伴随矩阵
const Matrix inv(const Matrix &A);  //求逆矩阵

矩阵类定义完成,接下来完成resize函数,swap_row比较简单此处不再展出

void Matrix::resize(int rows, int cols)
{
	int rs = this->rows();
	int cs = this->cols();
	if (rows == rs && cols == cs)
	{
		return;
	}
	else if (rows == rs && cols != cs)    //改列数
	{
		for (int i = 0;i < rows; i++)
		{
			DataArray[i].resize(cols);
		}
	}
	else if (rows != rs && cols == cs)   //改行数
	{
		DataArray.resize(rows);
		for (int i = rs; i < rows; i++)
		{
			DataArray[i].resize(cols);
		}
	}
	else										//二者都改
	{
		DataArray.resize(rows);
		for (int i = 0; i < rows; i++)
		{
			DataArray[i].resize(cols);
		}
	}
}

接下来进入正题,求行列式,代数余子式,伴随矩阵和逆矩阵。步骤如下:

1.求行列式|A|,因为需要计算的行列式阶数并不是很高,所以我选择的求行列式方式为使用公式: ∑ ( − 1 ) t a 1 p 1 a 2 p 2 a 1 p 3 . . . . . . a n p n \sum(-1)^ta_{1p_1}a_{2p_2}a_{1p_3}......a_{np_n} (1)ta1p1a2p2a1p3......anpn,该公式也比较容易实现。然而在完成该函数之前需要先完成 p 1 p_1 p1 p n p_n pn的全排列,以及排列完成后各逆序数:

1)排列算法函数,不了解可自行搜索,比较简单,大概实现即用一个vector<int> p存储一种排列然后用vector<<int>> q存储全排列。

void swap(vector<int>& v, int i, int j)
{
	int temp = v[i];
	v[i] = v[j];
	v[j] = temp;
}

void Permutation(vector<int> &p, vector<vector<int>> &q,int c) 
{
	if (c == ((unsigned int)p.size() - 1))
	{
		q.push_back(p);         
	}
	else
	{
		for (int i = c; i < (unsigned int)p.size(); i++)
		{
			swap(p, i, c);
			Permutation(p, q, c + 1);
			swap(p, i, c);
		}
	}
}

2)求逆序数t:

int Power(vector<int>& v)
{
	int count = 0;
	for (int i = 0; i < (unsigned int)v.size(); i++)
	{
		for (int j = i + 1; j < (unsigned int)v.size(); j++)
		{
			if (v[i] > v[j])
			{
				count += 1;
			}
		}
	}
	return count;
}

3)求行列式,上面两步完成后,求行列式的步骤变得极其简单:

const double det(const Matrix &A)
{
	if (!A.square())         //此处可自行修改
	{
		cout << "fail" << endl;
		return 0.0;
	}
	//完成p1到pn的排列组合
	vector<int> rs;           
	vector<vector<int> > I;
	for (int i = 0; i < A.rows(); i++)      //输入1-n
	{
		rs.push_back(i);
	}
	Permutation(rs, I);
	
	double result = 0.0;
	for (int i = 0; i < I.size(); i++)
	{
		rs= I[i];                        //取出一种排列
		int temp = pow(-1.0, (double)Power(rs));   //算出该排列的逆序数
		int row = 0;
		for (int j = 0; j < (unsigned int)rs.size(); j++)    //计算一种排列对应的乘积
		{
			int col = rs[j];
			temp *= A[row][col];
			row++;
		}
		result += temp;
	}
	return result;
}

2.完成求代数余子式的函数,将划去行列元素放入一个新的矩阵,然后求解(其实求出行列式后,剩下三个函数会变得极其简单)。

const double alge_cofactor(const Matrix &A, int row, int col)
{
	if (!A.square())
	{
		cout << "fail" << endl;
		return 0.0;
	}

	vector<int> rs;
	vector<vector<int> > I;
	vector<double> ret;
	Matrix B((A.rows() - 1), (A.cols() - 1));
	for (int i = 0; i < A.rows(); i++)     //把组成行列式的元素移到ret中
	{
		if (i == (row-1))
			continue;
		for (int j = 0; j < A.cols(); j++)
		{
			if (j == (col-1))
				continue;
			else
				ret.push_back(A[i][j]);
		}
	}
	
	int count = 0;                     //剩下的元素组成一个新的行列式
	for (int i = 0; i < B.rows(); i++)
	{
		for (int j = 0; j < B.cols(); j++)
		{
			B[i][j] = ret[count];
			count++;
		}
	}

	double result = det(B)*pow(-1, (double)(row + col));   
	return result;
}

3.求伴随矩阵,A*:

const Matrix adjoint(const Matrix &A)
{
	Matrix B(A.rows(), A.cols());

	for (int i = 0; i < A.rows(); i++)
	{
		for (int j = 0; j < A.cols(); j++)
		{
			B[i][j] = alge_cofactor(A, (j + 1), (i + 1));
		}
	}

	return B;
}

4.求逆矩阵,使用公式 A − 1 = A ∗ ∣ A ∣ A^{-1}=\frac{A^*}{|A|} \quad A1=AA即可:

const Matrix inv(const Matrix &A)
{
	if (det(A) == 0||A.rows()!=A.cols())
		return A;
	else
	{
		return (adjoint(A) / det(A));  //该处需要重载一下 / 函数声明:const Matrix operator/(const Matrix A, double a);实现矩阵乘一个分数或者说除以一个数
	}
}

只需要测试一下矩阵求逆是否正确,即可验证一下其余函数的正确性,测试结果:
在这里插入图片描述
虽然可能还存在着很多问题,但是基本上完成任务了。最后感谢那些为我提供参考的前辈们。

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值