求解方程组: A x = b Ax=b Ax=b
满足以下条件中的任一即可
系数矩阵 A A A的各阶顺序主子式均不等于零(充要);
系数矩阵 A A A是对称正定矩阵;
系数矩阵 A A A是严格对角占优矩阵,即对角线元素大于对应行的其余元素之和。
消元过程(第 k k k次消元):
{ a i j ( k ) = a i j ( k − 1 ) − a i k ( k − 1 ) a k k ( k − 1 ) a k j ( k − 1 ) = a i j ( k − 1 ) − l i k a k j ( k − 1 ) , i = k + 1 , k + 2 , . . . , n ; j = k + 1 , k + 2 , . . . , n b i ( k ) = b i ( k − 1 ) − l i k b k ( k − 1 ) , i = k + 1 , k + 2 , . . . , n l i k ≜ a i k ( k − 1 ) a k k ( k − 1 ) , i = k + 1 , k + 2 , . . . , n \begin{cases} &a_{ij}^{(k)}=a_{ij}^{(k-1)}-\frac{a_{ik}^{(k-1)}}{a_{kk}^{(k-1)}}a_{kj}^{(k-1)}=a_{ij}^{(k-1)}-l_{ik}a_{kj}^{(k-1)}, \\ &i=k+1,k+2,...,n; j=k+1,k+2,...,n \\ \\ &b_i^{(k)} = b_i^{(k-1)}- l_{ik}b_{k}^{(k-1)}, i=k+1,k+2,...,n \\ \\ &l_{ik} \triangleq \frac{a_{ik}^{(k-1)}}{a_{kk}^{(k-1)}}, i=k+1, k+2, ..., n \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧aij(k)=aij(k−1)−akk(k−1)aik(k−1)akj(k−1)=aij(k−1)−likakj(k−1),i=k+1,k+2,...,n;j=k+1,k+2,...,nbi(k)=bi(k−1)−likbk(k−1),i=k+1,k+2,...,nlik≜akk(k−1)aik(k−1),i=k+1,k+2,...,n
回代过程:
{ x n = b n ( n − 1 ) a n n ( n − 1 ) , x k = b k ( k − 1 ) − ∑ j = k + 1 n a k j ( k − 1 ) x j a k k ( k − 1 ) , k = n − 1 , n − 2 , . . . , 2 , 1 \left\{ \begin{aligned} x_n &= \frac{b_n^{(n-1)}}{a_{nn}^{(n-1)}},\\ x_k &= \frac{b_k^{(k-1)}-\sum\limits_{j=k+1}^{n}a_{kj}^{(k-1)}x_j}{a_{kk}^{(k-1)}}, k=n-1,n-2,...,2,1 \end{aligned} \right. ⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧xnxk=ann(n−1)bn(n−1),=akk(k−1)bk(k−1)−j=k+1∑nakj(k−1)xj,k=n−1,n−2,...,2,1
令运算量为乘除法个数,则
消元过程: N 1 = ∑ k = 1 n − 1 ( n − k ) 2 + 2 ( n − k ) = n 3 / 3 + n 2 / 2 − 5 n / 6 N_1=\sum\limits_{k=1}^{n-1}(n-k)^2+2(n-k)=n^3/3+n^2/2-5n/6 N1=k=1∑n−1(n−k)2+2(n−k)=n3/3+n2/2−5n/6
回代过程: N 2 = 1 + ( n − 1 ) + ∑ k = 1 n − 1 ( n − k ) = n 2 / 2 + n / 2 N_2=1 + (n-1) + \sum\limits_{k=1}^{n-1}(n-k)=n^2/2 + n/2 N2=1+(n−1)+k=1∑n−1(n−k)=n2/2+n/2
高斯消去法总运算量: N = N 1 + N 2 = n 3 / 3 + n 2 − n / 3 N=N_1+N_2=n^3/3+n^2-n/3 N=N1+N2=n3/3+n2−n/3
时间复杂度: O ( n 3 ) O(n^3) O(n3)
空间复杂度: O ( n 2 ) O(n^2) O(n2),开销为系数矩阵 A A A和一维数组 b b b
typedef float elem;
vector<elem> Gauss_Elimination(vector<vector<elem>>& A,
vector<elem>& b, elem epsilon){
/* 高斯消去法
参数简介:
A - n维的系数矩阵
b - 方程组等号右边的向量,维度1xn
epsilon - 矩阵元素的阈值,当主元过小时高斯消去法将数值不稳定
使用前的约定:
1. 确保A不为空,且Ax=b中各个参数的维度一致
注:执行完后,A和b将会改变
*/
int n = A.size();
vector<elem> x(n);
// 消元过程
for (int k=0; k<n-1; ++k){ // 第k+1步消元
// 主元太小,不能继续
if(abs(A[k][k]) < epsilon){
cout<<"The pivot element is too small. Process aborted."<<endl;
return {};
}
for (int i=k+1; i<n; ++i){ // l[i][k]
A[i][k] /= A[k][k];
}
// b[i]
for (int i=k+1; i<n; ++i){
b[i] -= A[i][k]*b[k];
}
// A[i][j]
for (int i=k+1; i<n; ++i){
for (int j=k+1; j<n; ++j){
A[i][j] -= A[i][k] * A[k][j];
}
}
}
// 回代过程
for (int k=n-1; k>=0; --k){
for (int j=k+1; j<n; ++j){
b[k] -= A[k][j] * x[j];
}
x[k] = b[k] / A[k][k];
}
return x;
}
( ∣ A ∣ ≠ 0 ) ⇏ ( a k k ( k − 1 ) ≠ 0 ) (\vert A \vert \neq 0) \nRightarrow (a_{kk}^{(k-1)} \neq 0) (∣A∣=0)⇏(akk(k−1)=0),即使 a k k ( k − 1 ) ≠ 0 a_{kk}^{(k-1)} \neq 0 akk(k−1)=0,但 ∣ a k k ( k − 1 ) ∣ \vert a_{kk}^{(k-1)}\vert ∣akk(k−1)∣很小,这就会引起其他元素数量级的剧增和舍入误差的增长,导致计算结果不可靠,甚至计算不能进行下去(上溢)。
相比经典的高斯消去法,在消元过程前额外多了按列选主元步骤和交换行步骤,其余流程是一致的。
按列选主元步骤的算法描述: 选取第 k k k列的主元,即寻找它所在的行 q q q,有:
q = arg max i ∈ [ k , n ) ∣ a i k ∣ q=\argmax\limits_{i\in [k, n)}\vert a_{ik}\vert q=i∈[k,n)argmax∣aik∣
交换行步骤的算法描述: 找到主元所在行 q q q后,分别交换 A A A和 b b b的第 k k k行和第 q q q行元素,即
{ s w a p ( a k j , a q j ) , j = k , k + 1 , . . . , n s w a p ( b k , b q ) \begin{cases} &\rm{swap}(a_{kj}, a_{qj}),j=k,k+1,...,n \\ & \rm{swap}(b_{k}, b_{q}) \end{cases} {swap(akj,aqj),j=k,k+1,...,nswap(bk,bq)
时间复杂度: O ( n 3 ) O(n^3) O(n3),增加的两个步骤的复杂度均为 O ( n ) O(n) O(n)
空间复杂度: O ( n 2 ) O(n^2) O(n2)
typedef float elem;
vector<elem> Gauss_Elimination_ColumnPivot(vector<vector<elem>>& A,
vector<elem>& b, elem epsilon){
/* 列主元的高斯消去法
参数简介:
A - n维的系数矩阵
b - 方程组等号右边的向量,维度1xn
epsilon - 矩阵元素的阈值,当主元过小时高斯消去法将数值不稳定
使用前的约定:
1. 确保A不为空,且Ax=b中各个参数的维度一致
注:执行完后,A和b将会改变
*/
int n = A.size();
vector<elem> x(n);
// 消元过程
for (int k=0; k<n-1; ++k){ // 第k+1步消元
elem maxf = 0;
int q; // 最大主元所在行
// 选主元
for (int i=k; i<n; ++i){
if(abs(maxf) < abs(A[i][k])){
maxf = A[i][k];
q = i;
}
}
// 主元太小,不能继续
if(abs(maxf) < epsilon){
cout<<"The pivot element is too small. Process aborted."<<endl;
return {};
}
// 交换行
if(q != k){
for (int j=k; j<n; ++j){
swap(A[q][j], A[k][j]);
}
swap(b[q], b[k]);
}
// 消元过程
for (int i=k+1; i<n; ++i){ // l[i][k]
A[i][k] /= A[k][k];
}
// b[i]
for (int i=k+1; i<n; ++i){
b[i] -= A[i][k]*b[k];
}
// A[i][j]
for (int i=k+1; i<n; ++i){
for (int j=k+1; j<n; ++j){
A[i][j] -= A[i][k] * A[k][j];
}
}
}
// 回代过程
for (int k=n-1; k>=0; --k){
for (int j=k+1; j<n; ++j){
b[k] -= A[k][j] * x[j];
}
x[k] = b[k] / A[k][k];
}
return x;
}
[1] 李乃成, 梅立泉. 数值分析[M]. 科学出版社, 2011.
笔者水平有限,如有错误欢迎批评指正~