编程语言
首页 > 编程语言> > [C++基础] Matrix类的实现(三)求行列式的值

[C++基础] Matrix类的实现(三)求行列式的值

作者:互联网

定义与解法

**定义:**n阶行列式等于所有取自不同行不同列的n个元素的乘积的代数和。
解法:

  1. 定义法:根据定义n阶行列式的值计算公式如下:
    ∣ a 11 a 12 . . . a 1 n a 21 a 22 . . . a 2 n . . . . . . . . . . . . a n 1 a n 2 . . . a n n ∣ = ∑ j 1 j 2 . . . j n ( − 1 ) τ ( j 1 j 2 . . . j n ) a 1 j 1 a 2 j 2 . . . a n j n \begin{vmatrix} a_{11}& a_{12} & ... & a_{1n} \\ a_{21}& a_{22} & ... & a_{2n} \\ ...& ... & ... & ... \\ a_{n1}& a_{n2}^{} & ... & a_{nn} \end{vmatrix} =\sum_{ j_{1}j_{2}...j_{n}}^{} (-1)^{\tau(j_{1}j_{2}...j_{n}) }a_{1j_{1}}a_{2j_{2}}...a_{nj_{n}} ∣∣∣∣∣∣∣∣​a11​a21​...an1​​a12​a22​...an2​​............​a1n​a2n​...ann​​∣∣∣∣∣∣∣∣​=j1​j2​...jn​∑​(−1)τ(j1​j2​...jn​)a1j1​​a2j2​​...anjn​​
    其中 τ ( j 1 j 2 . . . j n ) \tau(j_{1}j_{2}...j_{n}) τ(j1​j2​...jn​)为 j 1 j 2 . . . j n j_{1}j_{2}...j_{n} j1​j2​...jn​目前排列的逆序数。如果读者还对逆序数不清楚,可以百度一下,本文不做阐述。
    由于要对 j 1 j 2 . . . j n j_{1}j_{2}...j_{n} j1​j2​...jn​所有排列进行计算,总共有 j 1 j 2 . . . j n j_{1}j_{2}...j_{n} j1​j2​...jn​有 n ! n! n!项。
  2. 降阶法(展开法)
    降阶法我们需要用到代数余子式,因此在计算之前,先了解一下代数余子式
    代数余子式定义:
    ∣ a 11 a 12 . . . a 1 n a 21 a 22 . . . a 2 n . . . . . . . . . . . . a n 1 a n 2 . . . a n n ∣ \begin{vmatrix} a_{11}& a_{12} & ... & a_{1n} \\ a_{21}& a_{22} & ... & a_{2n} \\ ...& ... & ... & ... \\ a_{n1}& a_{n2}^{} & ... & a_{nn} \end{vmatrix} ∣∣∣∣∣∣∣∣​a11​a21​...an1​​a12​a22​...an2​​............​a1n​a2n​...ann​​∣∣∣∣∣∣∣∣​
    在上面行列式中划去元素 a i j a_{ij} aij​所在的第 i i i行第 j j j列,剩下的 ( n − 1 ) 2 {(n-1)}^{2} (n−1)2个元素按原来的排法构成一个 n − 1 n-1 n−1阶的行列式 M i j M_{ij} Mij​,称 M i j M_{ij} Mij​为元素 a i j a_{ij} aij​的余子式,Aij=(-1)i+j Mij A i j = ( n − 1 ) i + j M i j A_{ij}={(n-1)}^{i+j}M_{ij} Aij​=(n−1)i+jMij​称为元素的代数余子式。(如不能理解,建议草稿本上画一画)
    则行列式的值可以表示为(按第 i i i行展开) D = a i 1 A i 1 + a i 2 A i 2 + . . . + a i n A i n D=a_{i1}A_{i1}+a_{i2}A_{i2}+...+a_{in}A_{in} D=ai1​Ai1​+ai2​Ai2​+...+ain​Ain​
    对于每一个 A i k A_{ik} Aik​可以对其在进行展开。
  3. 变换法
    利用行列式中的某一行(列)的每一个数对应的加到某一行(列)上去,行列式值不变的性质,我们将行列式变为上三角或者下三角形,然后直接将对角线上的值进行相乘即可,如下图:
    ∣ 1 2 3 3 5 6 2 9 2 ∣ → ∣ 1 2 3 0 − 1 − 3 0 5 − 10 ∣ → ∣ 1 2 3 0 − 1 − 3 0 0 − 25 ∣ \begin{vmatrix} 1 & 2 & 3 \\ 3 & 5 & 6 \\ 2 & 9& 2 \end{vmatrix} \rightarrow \begin{vmatrix} 1 & 2 & 3 \\ 0 & -1 & -3 \\ 0 & 5 & -10 \end{vmatrix} \rightarrow \begin{vmatrix} 1 & 2 & 3 \\ 0 & -1 & -3 \\ 0 & 0 & -25 \end{vmatrix} ∣∣∣∣∣∣​132​259​362​∣∣∣∣∣∣​→∣∣∣∣∣∣​100​2−15​3−3−10​∣∣∣∣∣∣​→∣∣∣∣∣∣​100​2−10​3−3−25​∣∣∣∣∣∣​
    上述行列式的值就是 1 ∗ ( − 1 ) ∗ ( − 25 ) = 25 1*(-1)*(-25)=25 1∗(−1)∗(−25)=25

算法

本文求行列式的值的算法采用了将上述解法中(2)和(3)的结合,算法过程如下:

  1. 先对该矩阵进行判断是否可以进行行列式计算,不可则不执行,可以就执行下面步骤
  2. 从 a 11 a_{11} a11​开始,找到第一列不为 0 0 0的项 a i 1 a_{i1} ai1​,以 a i 1 a_{i1} ai1​为基准,对同一列的项所在的行进行对应的加加减减,最终目的是使得该行列式的第一列除了 a i 1 a_{i1} ai1​,其余项都为0
  3. 如果第2步发现第一列全是0,则该行列式值为0
  4. 按第一列展开,因为只有 a i 1 ≠ 0 a_{i1}≠0 ai1​​=0,所以行列式值 D n = ( − 1 ) i + 1 a i 1 A i 1 D_{n}={(-1)}^{i+1}a_{i1}A_{i1} Dn​=(−1)i+1ai1​Ai1​
    于是又以$A_{i1}为新的行列式,从2开始进行计算
  5. 如果行列式只有二阶了,退出循环并计算该二阶行列式的值 D 2 = a 11 ∗ a 22 − a 12 ∗ a 21 D_{2}=a_{11}*a_{22}-a_{12}*a_{21} D2​=a11​∗a22​−a12​∗a21​,最后融合到已经有结果的 D n D_{n} Dn​中去。

代码

if (rowCount != columnCount) return -2147483648.0;
	if (rowCount == 1) return GetItem(0, 0);
	if (rowCount == 2) return GetItem(0, 0) * GetItem(1, 1) - GetItem(0, 1) * GetItem(1, 0);
	Matrix temp(rowCount,columnCount);
	double res = 1.0;
	for (int i = 0; i < rowCount; i++)
	{
		for (int j = 0; j < columnCount; j++)
		{
			temp.SetItem(i, j, r[i][j]);
		}
	}
	while (true)
	{
		if (temp.GetRowCount() == 2) {
			res *= (temp.GetItem(0, 0) * temp.GetItem(1, 1) - temp.GetItem(0, 1) * temp.GetItem(1, 0));
			break;
		}
		//找到第一列第一个不为0的数,这个数不变
		int row = 0;
		while (row < temp.GetRowCount() && temp.GetItem(row, 0) == 0) row++;
		if (row == temp.GetRowCount()) { res *= 0; break; }
		//计算到结果中去
		res *= temp.GetItem(row, 0);
		res *= (row % 2 == 0 ? 1 : -1);
		//把该列除了选中的这个数全部置0
		for (int i = 0; i < temp.GetRowCount(); i++)
		{
			if(i == row || temp.GetItem(i, 0) == 0) continue;
			double coefficience = temp.GetItem(i, 0) / temp.GetItem(row, 0);
			for (int j = 1; j < columnCount; j++)
			{
				double val = temp.GetItem(i, j) - coefficience * temp.GetItem(row, j);
				temp.SetItem(i, j, val);
			}
			temp.SetItem(i, 0, 0);
		}
		Matrix p(temp.GetRowCount() - 1, temp.GetRowCount() - 1);
		for (int i = 0; i < p.GetRowCount(); i++)
		{
			for (int j = 0; j < p.GetColumnCount(); j++)
			{
				p.SetItem(i, j, temp.GetItem(i + 1, j + 1));
			}
		}
		temp.Reshape(p);
		
	}
	return res;

作者源码

https://github.com/PureZhao/BaseMathLib

项目里面找两个文件:

Matrix.h
Matrix.cpp

标签:...,Matrix,temp,C++,vmatrix,行列式,GetItem,row
来源: https://blog.csdn.net/weixin_40885067/article/details/112465241