【计算方法】#01 高斯消去法和列主元高斯消去法的原理简介及C++实现

【计算方法】#01 高斯消去法和列主元高斯消去法的原理简介及C++实现

      • 1. 高斯消去法
        • 1.1 算法的适用条件
        • 1.2 算法步骤和公式
        • 1.3 算法复杂度分析
        • 1.4 算法的C++实现
      • 2 列主元高斯消去法
        • 2.1 经典方法的致命问题
        • 2.2 按列选主元步骤的算法描述
        • 2.3 算法复杂度分析
        • 2.4 算法优势
        • 2.5 算法的C++实现
      • References

求解方程组: A x = b Ax=b Ax=b

1. 高斯消去法

1.1 算法的适用条件

满足以下条件中的任一即可

  1. 系数矩阵 A A A的各阶顺序主子式均不等于零(充要);

  2. 系数矩阵 A A A是对称正定矩阵;

  3. 系数矩阵 A A A是严格对角占优矩阵,即对角线元素大于对应行的其余元素之和。

1.2 算法步骤和公式

消元过程(第 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(k1)akk(k1)aik(k1)akj(k1)=aij(k1)likakj(k1),i=k+1,k+2,...,n;j=k+1,k+2,...,nbi(k)=bi(k1)likbk(k1),i=k+1,k+2,...,nlikakk(k1)aik(k1),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(n1)bn(n1),=akk(k1)bk(k1)j=k+1nakj(k1)xj,k=n1,n2,...,2,1

1.3 算法复杂度分析

令运算量为乘除法个数,则

消元过程: 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=1n1(nk)2+2(nk)=n3/3+n2/25n/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+(n1)+k=1n1(nk)=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+n2n/3

时间复杂度: O ( n 3 ) O(n^3) O(n3)

空间复杂度: O ( n 2 ) O(n^2) O(n2),开销为系数矩阵 A A A和一维数组 b b b

1.4 算法的C++实现

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;
}

2 列主元高斯消去法

2.1 经典方法的致命问题

( ∣ A ∣ ≠ 0 ) ⇏ ( a k k ( k − 1 ) ≠ 0 ) (\vert A \vert \neq 0) \nRightarrow (a_{kk}^{(k-1)} \neq 0) (A=0)(akk(k1)=0),即使 a k k ( k − 1 ) ≠ 0 a_{kk}^{(k-1)} \neq 0 akk(k1)=0,但 ∣ a k k ( k − 1 ) ∣ \vert a_{kk}^{(k-1)}\vert akk(k1)很小,这就会引起其他元素数量级的剧增和舍入误差的增长,导致计算结果不可靠,甚至计算不能进行下去(上溢)。

2.2 按列选主元步骤的算法描述

相比经典的高斯消去法,在消元过程前额外多了按列选主元步骤交换行步骤,其余流程是一致的。

按列选主元步骤的算法描述: 选取第 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)argmaxaik

交换行步骤的算法描述: 找到主元所在行 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)

2.3 算法复杂度分析

时间复杂度: O ( n 3 ) O(n^3) O(n3),增加的两个步骤的复杂度均为 O ( n ) O(n) O(n)

空间复杂度: O ( n 2 ) O(n^2) O(n2)

2.4 算法优势

  1. 由于 ∣ a i k ( k − 1 ) ∣ / ∣ a k k ( k − 1 ) ∣ ≤ 1   ( i = k + 1 , . . . , n ) \vert a_{ik}^{(k-1)}\vert/\vert a_{kk}^{(k-1)}\vert \le 1 \ (i=k+1, ..., n) aik(k1)/akk(k1)1 (i=k+1,...,n),列主元消去法有利于控制误差的传播,故具有较好的数值稳定性;

2.5 算法的C++实现

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;
}

References

[1] 李乃成, 梅立泉. 数值分析[M]. 科学出版社, 2011.

笔者水平有限,如有错误欢迎批评指正~

你可能感兴趣的:(C++,数值计算,数据结构与算法,学习笔记,数值计算,线性方程组求解的直接法,高斯消去法,C++)