• 【线性代数 & C++】求逆矩阵


    • 对于 n n n阶矩阵 A A A,如果有 n n n阶矩阵 B B B,使 A B = B A = E AB=BA=E AB=BA=E,则说 A A A是可逆的,并把 B B B称为 A A A逆矩阵.
    • A A A的逆矩阵记作 A − 1 A^{-1} A1,则 B = A − 1 B=A^{-1} B=A1.
    • ∣ A ∣ ≠ 0 \begin{vmatrix}A\end{vmatrix} \neq 0 A =0,则 A A A可逆,且 A − 1 = 1 ∣ A ∣ A ∗ A^{-1}= \frac{1}{\begin{vmatrix}A \end{vmatrix}}A^* A1=A1A.
    • 上式中, ∣ A ∣ \begin{vmatrix}A\end{vmatrix} A A A A的行列式, A ∗ A^* A A A A的伴随矩阵.
    • 根据上述内容,为求逆矩阵,需要分别求得矩阵行列式的值和矩阵的逆矩阵.

    1 矩阵行列式求值

    1.1 定义

    • n n n阶方阵 A A A的元素构成的行列式(各元素位置不变),称为 A A A的行列式,记作 ∣ A ∣ \begin{vmatrix}A \end{vmatrix} A d e t A detA detA.

    1.2 C++代码

    为便于管理函数,建立行列式类CDeterminant.

    2 求伴随矩阵

    2.1 定义

    • 行列式 ∣ A ∣ \begin{vmatrix}A\end{vmatrix} A 各元素的代数余子式 A i j A_{ij} Aij构成的如下矩阵 A ∗ = [ A 11 A 21 ⋯ A n 1 A 12 A 22 ⋯ A n 2 ⋮ ⋮ ⋮ A 1 n A 2 n ⋯ A n n ] , A^*=\begin{bmatrix}A_{11} & A_{21} & \cdots & A_{n1} \\A_{12} & A_{22} & \cdots & A_{n2} \\ \vdots & \vdots && \vdots \\A_{1n} & A_{2n} &\cdots & A_{nn}\end{bmatrix}, A= A11A12A1nA21A22A2nAn1An2Ann ,称为矩阵 A A A伴随矩阵.
    • 注意:伴随矩阵 A ∗ A^* A中元素的位置与对应行列式 ∣ A ∣ \begin{vmatrix}A\end{vmatrix} A 中元素的位置呈转置关系.

    2.2 C++代码

    2.2.1 求余子式
    • 由定义可知,求伴随矩阵,需先求行列式各元素的代数余子式.
    • 求代数余子式,需先求余子式.
    • 故,在CDeterminant类中增加一个求行列式余子式的成员函数GetDetRem().
    //在CDeterminant.h声明成员函数
    static bool GetDetRem
    (
        const vector<vector<double>> &vvDetInput, //原始行列式
        int i,  //待求余子式元素的行号
        int j,  //待求余子式元素的列号
        vector<vector<double>> &vvDetRet    //求得的余子式
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //在CDeterminant.cpp中定义成员函数
    bool CDeterminant::GetDetRem
    (
        const vector<vector<double>> &vvDetInput, 
        int i, 
        int j,
        vector<vector<double>> &vvDetRet
    )
    {
        if (false == IsDet(vvDetInput))//形参是否符合行列式格式要求
            return false;
    
        vvDetRet.clear();
        vvDetRet = vvDetInput;
    
        //删除元素所在的行
        vvDetRet.erase(vvDetRet.cbegin() + i);
        for (int i = 0; i < vvDetRet.size(); i++)
        {
            //删除元素所在的列
            vvDetRet[i].erase(vvDetRet[i].cbegin() + j);
        }
        
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    2.2.2 求伴随矩阵
    • 在CMatrix类中添加GetAdjointMat函数,用于求伴随矩阵.其思路是:
      1. 按列逐行取得矩阵的元素;
      2. 求相应的余子式
      3. 对余子式求值
      4. 求代数余子式
      5. 将代数余子式的值,按行填入新矩阵
      6. 得到伴随矩阵
    //在CMatrix.h中声明成员函数
    static bool GetAdjointMat
    (
    const vector<vector<double>> &vvMatInput,
    vector<vector<double>> &vvMatRet
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //在CMatrix.cpp中定义成员函数
    bool CMatrix::GetAdjointMat
    (
      const vector<vector<double>> &vvMatInput,
      vector<vector<double>> &vvMatRet
    )
    {
      //判断vector变量是否符合行列式格式
      if (false == CDeterminant::IsDet(vvMatInput))
        return false;
      
      vvMatRet.clear();
      vector<double> vTemp;//临时存储伴随矩阵的行元素
      vector<vector<double>> vvDetTemp;//临时存储余子式
      double iDetValTemp;//临时存储余子式的值
      //按列循环
      for (int i = 0; i < vvMatInput[0].size(); i++)
      {
        vTemp.clear();
        //按行循环
        for (int j = 0; j < vvMatInput.size(); j++)
        {
          //求余子式
          vvDetTemp.clear();
          CDeterminant::GetDetRem(vvMatInput, j, i, vvDetTemp);
          //余子式求值
          iDetValTemp = 0;
          CDeterminant::GetDetValByDef(vvDetTemp, iDetValTemp);
          //求代数余子式
          iDetValTemp = (pow(-1, i + j) * iDetValTemp);
          //代数余子式的值填入新矩阵的行元素中
          vTemp.push_back(iDetValTemp);
        }  
        //行元素填入新矩阵中
        vvMatRet.push_back(vTemp);  
      }  
      
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3 求逆矩阵

    • 利用前面求得的 ∣ A ∣ \begin{vmatrix}A \end{vmatrix} A A ∗ A^* A,按照公式 A − 1 = 1 ∣ A ∣ A ∗ A^{-1}= \frac{1}{\begin{vmatrix}A \end{vmatrix}}A^* A1=A1A,可以求得 A A A的逆矩阵.
    • 在CMatrix类中增加GetInverseMat函数,以实现上述功能.
    //在CMatrix.h中声明函数
    static bool GetInverseMat
    (
    const vector<vector<double>> &vvMatInput,
    vector<vector<double>> &vvInverseMat
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //在CMatrix.cpp中定义函数
    bool CMatrix::GetInverseMat
    (
      const vector<vector<double>> &vvMatInput,
      vector<vector<double>> &vvInverseMat
    )
    {
      if (false == CDeterminant::IsDet(vvMatInput))
        return false;
    
      //方阵行列式值不等于0时,方阵可逆
      double fDetVal;
      CDeterminant::GetDetValByDef(vvMatInput, fDetVal);
      if (0 == fDetVal)
        return false;  
      fDetVal = 1.0 / fDetVal;
    
      vector<vector<double>> vvMatTemp;
      GetAdjointMat(vvMatInput, vvMatTemp);//求伴随矩阵
    
      vvInverseMat.clear();
      MatMulti(fDetVal, vvMatTemp, vvInverseMat);//求数与矩阵相乘
    
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4 测试

    //在test.cpp中测试
    #include 
    #include 
    #include 
    
    #include "CMatrix.h"
    
    using namespace std;
    
    bool PrintMat
    (
      const vector<vector<double>> &vvMat
    )
    {
      for (int i = 0; i < vvMat.size(); i++)
      {
        for (int j = 0; j < vvMat[i].size(); j++)
        {
          cout << setw(5) << vvMat[i][j];
        }
        cout << endl;
      }
      
      return true;
    }
    
    int main()
    {
      vector<vector<double>> vvMatA{{ 1, 2, 3},
                                    { 2, 2, 1},
                                    { 3, 4, 3}};
      
      vector<vector<double>> vvMatRet;
    
      if (false == CMatrix::GetInverseMat(vvMatA, vvMatRet))
      {
        cout << "计算失败" << endl;
      }
      else
      {
        PrintMat(vvMatRet);
      } 
    
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述


    1. 引用文献:《工程数学 线性代数(第五版)》同济大学数学系编,高等教育出版社.
    2. 以上为个人学习、练习的记录,如有错误,欢迎指正.
  • 相关阅读:
    用友畅捷通文吉:如何通过智能运维提升稳定性保障
    免费研讨会 | 邀您体验 Ansys Zemax Enterprise 的 STAR 模块
    【论文阅读】—— PointNet
    【数据结构】期中测试1
    [尚硅谷React笔记]——第2章 React面向组件编程
    《第一堂棒球课》:王牌左外野·棒球7号位
    Sqoop概述 第1关:Sqoop概述
    中文编程工具免费版下载,中文开发语言工具免费版下载
    【SQL】数据库事务
    jenkins+centos7上传发布net6+gitlab
  • 原文地址:https://blog.csdn.net/qq_26390449/article/details/138120360