【线性代数 & 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} A−1,则 B = A − 1 B=A^{-1} B=A−1.
  • 若 ∣ 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^* A−1=∣A∣1A∗.
  • 上式中, ∣ 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∗= A11A12⋮A1nA21A22⋮A2n⋯⋯⋯An1An2⋮Ann ,称为矩阵 A A A的伴随矩阵.
  • 注意:伴随矩阵 A ∗ A^* A∗中元素的位置与对应行列式 ∣ A ∣ \begin{vmatrix}A\end{vmatrix} A 中元素的位置呈转置关系.

2.2 C++代码

2.2.1 求余子式
  • 由定义可知,求伴随矩阵,需先求行列式各元素的代数余子式.
  • 求代数余子式,需先求余子式.
  • 故,在CDeterminant类中增加一个求行列式余子式的成员函数GetDetRem().
cpp 复制代码
//在CDeterminant.h声明成员函数
static bool GetDetRem
(
    const vector<vector<double>> &vvDetInput, //原始行列式
    int i,  //待求余子式元素的行号
    int j,  //待求余子式元素的列号
    vector<vector<double>> &vvDetRet    //求得的余子式
);
cpp 复制代码
//在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;
}
2.2.2 求伴随矩阵
  • 在CMatrix类中添加GetAdjointMat函数,用于求伴随矩阵.其思路是:
    1. 按列逐行取得矩阵的元素;
    2. 求相应的余子式
    3. 对余子式求值
    4. 求代数余子式
    5. 将代数余子式的值,按行填入新矩阵
    6. 得到伴随矩阵
cpp 复制代码
//在CMatrix.h中声明成员函数
static bool GetAdjointMat
(
const vector<vector<double>> &vvMatInput,
vector<vector<double>> &vvMatRet
);
cpp 复制代码
//在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;
}

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^* A−1=∣A∣1A∗,可以求得 A A A的逆矩阵.
  • 在CMatrix类中增加GetInverseMat函数,以实现上述功能.
cpp 复制代码
//在CMatrix.h中声明函数
static bool GetInverseMat
(
const vector<vector<double>> &vvMatInput,
vector<vector<double>> &vvInverseMat
);
cpp 复制代码
//在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;
}

4 测试

cpp 复制代码
//在test.cpp中测试
#include <iostream>
#include <iomanip>
#include <vector>

#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. 以上为个人学习、练习的记录,如有错误,欢迎指正.
相关推荐
娅娅梨26 分钟前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
兵哥工控31 分钟前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
我爱工作&工作love我38 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h1 小时前
探索 C++20:C++ 的新纪元
c++·c++20
lexusv8ls600h1 小时前
C++20 中最优雅的那个小特性 - Ranges
c++·c++20
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
好睡凯1 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
依旧阳光的老码农2 小时前
标准C++ 字符串
开发语言·c++
白-胖-子2 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-成绩排序
c++·算法·蓝桥杯·真题·蓝桥等考