前言:
? ? ? ? 上次博客,我寫了一篇關(guān)于定義矩陣除法并且代碼的文章。矩陣除法或許用處不大,不過在那一篇文章中,我認(rèn)為比較好的一點是告訴了大家一種計算方法,即:若矩陣??已知且可逆,矩陣??已知,并且??,求解矩陣 B 。我認(rèn)為這種初等行變換的方法還是挺好的。
? ? ? ? 在本篇文章中,我和大家探討一下線性代數(shù)里面一個重要的知識——線性方程組及其解法。
一、線性代數(shù)知識回顧:
我們先探討一下二元一次方程組的解法:
????????相信這個解法大家已經(jīng)很熟悉了,將第一個式子的 -2 倍加到第二個式子上,就可以消掉第二個式子中的 x 了,然后第二個式子就只剩下 y 一個未知數(shù)了,就可以輕松解出 y ,然后將 y 代入第一個式子,就可以輕松解出 x ,到此,二元一次方程組求解完成。
? ? ? ? 從幾何意義上看,這兩個方程對應(yīng)著二維平面上的兩條直線,并且這兩條直線交于一點(1,1),因此有唯一解。
? ? ? ? 有人可能會想到,不是所有的二元一次方程組都有解,因此我們看一看下面的例子:?
? ? ? ? ?大家看到,這個這個將第二個式子中兩個未知數(shù)都化沒了,并且觀察這個方程組可知,它有無數(shù)解,其實容易看到,第二個式子就是第一個式子的 2 倍,實際上,這兩個式子是等價的,第二個式子所描述的信息完全可以用第一個式子描述,也就是說這個方程組中 “有效方程” 的個數(shù)為 1 ,而只靠一個式子無法固定兩個未知數(shù),因此方程組有無數(shù)解。
? ? ? ? 從幾何意義上看,這兩個式子就是二維平面中的兩個直線,而這兩個直線是重合的,也就是說,兩個直線相交的點有無數(shù)個,即:方程組有無數(shù)解。
? ? ? ? 那么,二元一次方程組有沒有可能無解呢?看看下面的例子:
? ? ? ? ?可以看到,消元后,第二個方程變?yōu)榱艘粋€不可能成立的式子。容易看出,這兩個方程是矛盾的,因此是無解的。
? ? ? ? 從幾何意義上看,這兩個二維平面上的直線平行且不重合,沒有交點,因此無解。
????????從上面二元一次方程組的回顧中,我們可以將方程組推廣到 n 維情形:
?????????同樣按照上面的消元方法,不過這次稍微復(fù)雜,首先消去第 2 個到第 n 個方程的未知數(shù)??然后消去第 3 個到第 n 個方程的未知數(shù)??,以此類推,直到消去最后一個方程的未知數(shù)??,然后自下而上,先求出??,代入倒數(shù)第二個方程,求出??,代入倒數(shù)第三個方程,依次類推,便可求出方程組的解。大家仔細(xì)看看消元的過程,是不是和初等行變換十分像,我們其實可以將上述方程組這樣表示:
設(shè)? ? ? ? ? ??? ? ? ? ? ?? ? ? ? ? ?
上述方程組可以表示為:
為了表示方便,我們引入增廣矩陣:
? ? ? ? ?當(dāng)我們對未知數(shù)規(guī)定書寫順序,那么增廣矩陣就和線性方程組就?一 一 對應(yīng)了,對方程組進(jìn)行消元就等價于對增廣矩陣??進(jìn)行初等行變換,方程組的有效方程的個數(shù)就等于增廣矩陣的秩,也等于系數(shù)矩陣的秩,也就是說,如果系數(shù)矩陣滿秩,那么方程組有唯一解。當(dāng)系數(shù)矩陣不滿秩時,若沒有矛盾方程出現(xiàn),則方程組有無數(shù)解,若有矛盾方程出現(xiàn),則方程組無解。
? ? ? ? 從幾何意義來看,這 n 個方程組相當(dāng)于 n 維空間中 n 個 n-1 維的平面。n 個平面交于一點等價于方程組中的 “有效方程” 的個數(shù)為 n ,等價于系數(shù)矩陣??滿秩,等價于增廣矩陣??的秩為 n ,等價于方程組有唯一解。
二、算法描述:
? ? ? ? 輸入系數(shù)矩陣 ?以及 向量??,求解向量??,使得??。
? ? ? ? 1. 求出增廣矩陣
? ? ? ? 2. 將增廣矩陣初等行變換,化為上三角形,在這個過程中,判斷增廣矩陣的秩是否是 n ,如果不是 n ,則說明方程組無解或有無數(shù)解。
? ? ? ? 3. 自下而上依次計算出??。
? ? ? ? ?詳情請看下面代碼:
三、代碼實現(xiàn):
????????類定義為:
class Mat
{
public:
int m = 1, n = 1; //行數(shù)和列數(shù)
double mat[N][N] = { 0 }; //矩陣開始的元素
Mat() {}
Mat(int mm, int nn)
{
m = mm; n = nn;
}
void create();//創(chuàng)建矩陣
void Print();//打印矩陣
void augmat(Mat a, Mat b);//求矩陣 a 和向量 b 的增廣矩陣
bool solve(Mat a, Mat b); //求線性方程組的解
};
? ? ? ? 其中solve函數(shù)求解線性方程組,其定義如下:
bool Mat::solve(Mat a, Mat b) //a 為方陣 ,b 為列向量
//求線性方程組的解(ax=b ,求 x),矩陣 a 為方陣并且方程組有唯一解時返回 true
{
if (a.n != a.m)//只求解是方陣時的情形
{
cout << "系數(shù)矩陣不是方陣" << endl;
return false; //返回false
}
m = a.n; n = 1; //解向量中必定有 a.n( a.m )個分量,是 a.n * 1 的列向量
Mat aa;
aa.augmat(a, b); //求增廣矩陣
//下面代碼將增廣矩陣化為上三角矩陣,并判斷增廣矩陣秩是否為 n
for (int i = 1; i <= aa.m; i++)
{
//尋找第 i 列不為零的元素
int k;
for (k = i; k <= aa.m; k++)
{
if (fabs(aa.mat[k][i]) > 1e-10) //滿足這個條件時,認(rèn)為這個元素不為0
break;
}
if (k <= aa.m)//說明第 i 列有不為0的元素
{
//交換第 i 行和第 k 行所有元素
for (int j = i; j <= aa.n; j++)//從第 i 個元素交換即可,因為前面的元素都為0
{//使用aa.mat[0][j]作為中間變量交換元素
aa.mat[0][j] = aa.mat[i][j]; aa.mat[i][j] = aa.mat[k][j]; aa.mat[k][j] = aa.mat[0][j];
}
double c;//倍數(shù)
for (int j = i + 1; j <= aa.m; j++)
{
c = -aa.mat[j][i] / aa.mat[i][i];
for (k = i; k <= aa.n; k++)
{
aa.mat[j][k] += c * aa.mat[i][k];//第 i 行 a 倍加到第 j 行
}
}
}
else //沒有找到則說明系數(shù)矩陣秩不為 n ,說明方程組中有效方程的個數(shù)小于 n
{
cout << "系數(shù)矩陣奇異,線性方程組無解或有無數(shù)解" << endl;
return false;
}
}
//自下而上求解
for (int i = a.m; i >= 1; i--)
{
mat[i][1] = aa.mat[i][aa.n];
for (int j = a.m; j > i; j--)
{
mat[i][1] -= mat[j][1] * aa.mat[i][j];
}
mat[i][1] /= aa.mat[i][i];
}
return true;
}
線性方程組的求解就完成了,這種求解方法叫 “高斯消元法” 。下面附上完整代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-422319.html
#include<iostream>
#include <cmath>
#define N 10
using namespace std;
class Mat
{
public:
int m = 1, n = 1; //行數(shù)和列數(shù)
double mat[N][N] = { 0 }; //矩陣開始的元素
Mat() {}
Mat(int mm, int nn)
{
m = mm; n = nn;
}
void create();//創(chuàng)建矩陣
void Print();//打印矩陣
void augmat(Mat a, Mat b);//求矩陣 a 和向量 b 的增廣矩陣
bool solve(Mat a, Mat b); //求線性方程組的解
};
void Mat::create()
{
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> mat[i][j];
}
}
}
void Mat::Print()
{
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
cout << mat[i][j] << "\t";
}
cout << endl;
}
}
void Mat::augmat(Mat a, Mat b)//求矩陣 a 和向量 b 的增廣矩陣
{
m = a.m; n = a.n + 1;
for (int i = 1; i <= a.m; i++)
{
for (int j = 1; j <= a.n; j++)
{
mat[i][j] = a.mat[i][j];
}
mat[i][n] = b.mat[i][1];
}
}
bool Mat::solve(Mat a, Mat b) //a 為方陣 ,b 為列向量
//求線性方程組的解(ax=b ,求 x),矩陣 a 為方陣并且方程組有唯一解時返回 true
{
if (a.n != a.m)//只求解是方陣時的情形
{
cout << "系數(shù)矩陣不是方陣" << endl;
return false; //返回false
}
m = a.n; n = 1; //解向量中必定有 a.n( a.m )個分量,是 a.n * 1 的列向量
Mat aa;
aa.augmat(a, b); //求增廣矩陣
//下面代碼將增廣矩陣化為上三角矩陣,并判斷增廣矩陣秩是否為 n
for (int i = 1; i <= aa.m; i++)
{
//尋找第 i 列不為零的元素
int k;
for (k = i; k <= aa.m; k++)
{
if (fabs(aa.mat[k][i]) > 1e-10) //滿足這個條件時,認(rèn)為這個元素不為0
break;
}
if (k <= aa.m)//說明第 i 列有不為0的元素
{
//交換第 i 行和第 k 行所有元素
for (int j = i; j <= aa.n; j++)//從第 i 個元素交換即可,因為前面的元素都為0
{//使用aa.mat[0][j]作為中間變量交換元素
aa.mat[0][j] = aa.mat[i][j]; aa.mat[i][j] = aa.mat[k][j]; aa.mat[k][j] = aa.mat[0][j];
}
double c;//倍數(shù)
for (int j = i + 1; j <= aa.m; j++)
{
c = -aa.mat[j][i] / aa.mat[i][i];
for (k = i; k <= aa.n; k++)
{
aa.mat[j][k] += c * aa.mat[i][k];//第 i 行 a 倍加到第 j 行
}
}
}
else //沒有找到則說明系數(shù)矩陣秩不為 n ,說明方程組中有效方程的個數(shù)小于 n
{
cout << "系數(shù)矩陣奇異,線性方程組無解或有無數(shù)解" << endl;
return false;
}
}
//自下而上求解
for (int i = a.m; i >= 1; i--)
{
mat[i][1] = aa.mat[i][aa.n];
for (int j = a.m; j > i; j--)
{
mat[i][1] -= mat[j][1] * aa.mat[i][j];
}
mat[i][1] /= aa.mat[i][i];
}
return true;
}
int main()
{
Mat a(3, 3), b(3, 1);
cout << "請輸入 " << a.m << "*" << a.n << " 的矩陣:" << endl;
a.create();
cout << "請輸入 " << b.m << "*" << b.n << " 的列向量:" << endl;
b.create();
Mat x;
if (x.solve(a, b))//求線性方程組的解向量
{
cout << "解向量如下:" << endl << endl;
x.Print();
}
return 0;
}
若有不足之處,歡迎大家指正!文章來源地址http://www.zghlxwxcb.cn/news/detail-422319.html
到了這里,關(guān)于線性代數(shù)代碼實現(xiàn)(七)求解線性方程組(C++)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!