关于雅克比迭代, 高斯塞德尔迭代以及SOR迭代的C++实现


算法不难,只要理解Jacobi的算法另外两种就很简单了,因为他们都是建立在Jacobi迭代的基础上.
首先讲一下程序,主要是由输入功能,和迭代方式调用功能实现块构成的.

点击这里下载源码.
提取码:mlpb

程序变量

int m; //m*n的系数矩阵
int max_times;// z最大迭代次数
int times = 0;//当前迭代次数
//int mx_mis = 99999999;
string choice;//功能选择
double mis;//误差范围
double mtrx[sz][sz];//系数矩阵
double b[sz];//常数矩阵
double init[sz];//初始向量
double ans[sz];//答案
//double max_mis[sz];//

主程序

int main()
{
    input();

    func();

    return 0;
}

输入功能

这里就是输入计算需要的系数矩阵,常数矩阵等基本条件.

void  input()
{
    cout<<"请输入迭代方式(J,GS,SOR)"<<endl;
    cin>>choice;

    cout << "请输入m" << endl;
    cin >> m;

    cout << "请输入系数矩阵m*n(m)" << endl;
    for ( int i = 0; i < m; i++ )
    {
        for ( int j = 0; j < m; j++ )
        {
            cin >> mtrx[i][j];
        }
    }

    cout << "请输入常数矩阵b:" << endl;
    for ( int i = 0; i < m; i++ )
    {
        cin >> b[i];
    }

    cout << "请输入初始向量" << endl;
    for ( int i = 0; i < m; i++ )
    {
        cin >> init[i];
        ans[i] = init[i];
    }

    cout << "请输入最大迭代次数:" << endl;
    cin >> max_times;

//    cout << endl << "请输入最大误差:"<<endl;
//         cin>>mis;
}

输出功能

迭代结束后进行输出

void output()
{

    cout << "迭代" << times+1 << "次,答案是" << endl;
    for ( int i = 0; i < m; i++ )
    {
//        cout << init[i] << endl;
        printf ( "%.4f\t", init[i] );
    }
    printf ( "\n" );
}

迭代调用功能

为了main函数里干净点,把功能函数统统放进func里

void func()
{
    if(choice=="J")
        Jacobi();
    else if(choice=="GS")
        GS();
    else
        SOR();
}

Jacobi迭代

首先确立迭代截止条件,就是迭代次数达到所设(或及误差满足条件,但我这里么有实现).然后在while里进行具体迭代.
形如:
[ 10 − 1 − 2 − 1 10 − 2 − 1 − 1 5 ] [ x 1 x 2 x 3 ] = [ 7.2 8.3 4.2 ] \left[ \begin{matrix} 10 & -1 & -2 \\ -1 & 10 & -2 \\ -1 & -1 & 5 \end{matrix} \right] \left[ \begin{matrix} x_1\\ x_2 \\ x_3 \end{matrix} \right] = \left[ \begin{matrix} 7.2\\ 8.3\\ 4.2 \end{matrix} \right] 10111101225x1x2x3=7.28.34.2
这个矩阵.进行Jacobi迭代时,按照迭代格式
x i k + 1 = 1 a i i ( d i − ∑ j = 1 i − 1 a i j k − ∑ j = i + 1 n a i j k ) x_i^{k+1}= \frac {1} {a_{ii}} \left(d_i- \sum_{j=1}^{i-1}a_{ij}^{k}-\sum_{j=i+1}^{n}a_{ij}^k \right) xik+1=aii1(dij=1i1aijkj=i+1naijk)
需要先进行类似矩阵乘法的操作,将其求和并用 d i d_i di减去,然后除 a i i a_{ii} aii,得到的值就是 x i k + 1 x_i^{k+1} xik+1

void Jacobi()
{
    do
    {
        mx_mis = 0;
        //根据初始向量进行向量乘法.求出每一行对应的解
        //把结果放在ans中
        for ( int i = 0; i < m; i++ )
        {
            double sum = 0;

            for ( int j = 0; j < m; j++ )
            {
                if ( j != i )
                {
                    sum += init[j] * mtrx[i][j];
                }
            }
            ans[i] = ( b[i] - sum  ) / mtrx[i][i];
            //            if ( i > 0 )
            if ( fabs ( init[i] - ans[i] ) > mx_mis )
                mx_mis = fabs ( init[i] - ans[i] );
        }
        //迭代完成一次, 就更新一次init数组,以便下一次迭代
        for ( int i = 0; i < m; i++ )
        {
            init[i] = ans[i];
        }
//        mx_mis=max_mis[0];
//        for(int i=0;i<m;i++)
//        {
//            if(max_mis[i]>mx_mis)
//                mx_mis= max_mis[i];
//        }
        output();
    }
    while ( ( times++ < max_times ) && ( mis_range < mx_mis ) );
}

GS迭代

迭代格式是 x i k + 1 = 1 a i i ( d i − ∑ j = 1 i − 1 a i j k − ∑ j = i + 1 n a i j k + 1 ) x_i^{k+1}= \frac {1} {a_{ii}} \left(d_i- \sum_{j=1}^{i-1}a_{ij}^{k}-\sum_{j=i+1}^{n}a_{ij}^{k+1} \right) xik+1=aii1(dij=1i1aijkj=i+1naijk+1)
对比Jacobi迭代,在代码上的实现区别就是不需要ans数组暂存,直接将新的 x i k + 1 x_i^{k+1} xik+1赋给init[i].自然也不需要init和ans的同步.

void GS()
{
    double temp;
    do
    {
        mx_mis = 0;
        //根据初始向量进行向量乘法.求出每一行对应的解
        for ( int i = 0; i < m; i++ )
        {
            double sum = 0;
            for ( int j = 0; j < m; j++ )
            {
                if ( j != i )
                {
                    sum += init[j] * mtrx[i][j];
                }
            }
            temp = init[i];
            init[i] = ( b[i] - sum  ) / mtrx[i][i];
            if ( fabs ( init[i] - temp ) > mx_mis )
                mx_mis = fabs ( init[i] - temp );
        }
        output();
    }
    while ( (  times++ < max_times ) && ( mx_mis > mis_range ) );
}

SOR迭代

void SOR()
{
    double w;
    cout << "请输入松弛因子w:" << endl;
    cin >> w;
    double temp;
    do
    {
        mx_mis = 0;
        //根据初始向量进行向量乘法.求出每一行对应的解
        for ( int i = 0; i < m; i++ )
        {
            double sum = 0;
            for ( int j = 0; j < m; j++ )
            {
                if ( j != i )
                {
                    sum += init[j] * mtrx[i][j];
                }
            }
            temp = init[i];
            init[i] = init[i] + w * ( ( b[i] - sum  ) / mtrx[i][i]  - init[i] );
            if ( fabs ( init[i] - temp ) > mx_mis )
                mx_mis = fabs ( init[i] - temp );
        }
        output();
    }while ( (  times++ < max_times ) && ( mx_mis > mis_range ) );
}

上面是注意分析,下面是源代码.
如有错误请多指正.

#include<iostream>
#include<math.h>
#define sz 10

using namespace std;

/*****************************
@Jacobi迭代解线性方程组
@author:jawi
@date:2020/03/03
@tip:本程序默认输入矩阵均为理想矩阵
*****************************/

void input();
void Jacobi();
void GS();
void SOR();
void func();
void output();

int m; //m*n的系数矩阵
int max_times;// z最大迭代次数
int times = 0;//当前迭代次数
double mx_mis = 0;//当前最大误差
string choice;//功能选择
double mis;//误差范围
double mtrx[sz][sz];//系数矩阵
double b[sz];//常数矩阵
double init[sz];//初始向量
double ans[sz];//答案
double mis_range;//最大误差范围

int main()
{
    input();

    func();

    return 0;
}

void func()
{
    if ( choice == "J" )
        Jacobi();
    else if ( choice == "GS" )
        GS();
    else
        SOR();
}

void  input()
{
    cout << "请输入迭代方式(J,GS,SOR)" << endl;
    cin >> choice;

    cout << "请输入m" << endl;
    cin >> m;

    cout << "请输入系数矩阵m*n(m)" << endl;
    for ( int i = 0; i < m; i++ )
    {
        for ( int j = 0; j < m; j++ )
        {
            cin >> mtrx[i][j];
        }
    }

    cout << "请输入常数矩阵b:" << endl;
    for ( int i = 0; i < m; i++ )
    {
        cin >> b[i];
    }

    cout << "请输入初始向量" << endl;
    for ( int i = 0; i < m; i++ )
    {
        cin >> init[i];
        ans[i] = init[i];
    }

    cout << "请输入最大迭代次数:" << endl;
    cin >> max_times;

    cout << "请输入最大误差范围:" << endl;
    cin >> mis_range;

//    cout << endl << "请输入最大误差:"<<endl;
//         cin>>mis;
}

void Jacobi()
{
    do
    {
        mx_mis = 0;
        //根据初始向量进行向量乘法.求出每一行对应的解
        //把结果放在ans中
        for ( int i = 0; i < m; i++ )
        {
            double sum = 0;

            for ( int j = 0; j < m; j++ )
            {
                if ( j != i )
                {
                    sum += init[j] * mtrx[i][j];
                }
            }
            ans[i] = ( b[i] - sum  ) / mtrx[i][i];
            //            if ( i > 0 )
            if ( fabs ( init[i] - ans[i] ) > mx_mis )
                mx_mis = fabs ( init[i] - ans[i] );
        }
        //迭代完成一次, 就更新一次init数组,以便下一次迭代
        for ( int i = 0; i < m; i++ )
        {
            init[i] = ans[i];
        }
//        mx_mis=max_mis[0];
//        for(int i=0;i<m;i++)
//        {
//            if(max_mis[i]>mx_mis)
//                mx_mis= max_mis[i];
//        }
        output();
    }
    while ( ( times++ < max_times ) && ( mis_range < mx_mis ) );
}

void GS()
{
    double temp;
    do
    {
        mx_mis = 0;
        //根据初始向量进行向量乘法.求出每一行对应的解
        for ( int i = 0; i < m; i++ )
        {
            double sum = 0;
            for ( int j = 0; j < m; j++ )
            {
                if ( j != i )
                {
                    sum += init[j] * mtrx[i][j];
                }
            }
            temp = init[i];
            init[i] = ( b[i] - sum  ) / mtrx[i][i];
            if ( fabs ( init[i] - temp ) > mx_mis )
                mx_mis = fabs ( init[i] - temp );
        }
        output();
    }
    while ( (  times++ < max_times ) && ( mx_mis > mis_range ) );
}

void SOR()
{
    double w;
    cout << "请输入松弛因子w:" << endl;
    cin >> w;
    double temp;
    do
    {
        mx_mis = 0;
        //根据初始向量进行向量乘法.求出每一行对应的解
        for ( int i = 0; i < m; i++ )
        {
            double sum = 0;
            for ( int j = 0; j < m; j++ )
            {
                if ( j != i )
                {
                    sum += init[j] * mtrx[i][j];
                }
            }
            temp = init[i];
            init[i] = init[i] + w * ( ( b[i] - sum  ) / mtrx[i][i]  - init[i] );
            if ( fabs ( init[i] - temp ) > mx_mis )
                mx_mis = fabs ( init[i] - temp );
        }
        output();
    }while ( (  times++ < max_times ) && ( mx_mis > mis_range ) );
}

void output()
{

    cout << "迭代" << times+1 << "次,答案是" << endl;
    for ( int i = 0; i < m; i++ )
    {
//        cout << init[i] << endl;
        printf ( "%.4f\t", init[i] );
    }
    printf ( "\n" );
}
  • 10
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
高斯赛德尔迭代雅克迭代都是求解线性方程组的迭代方法。它们的区别在于迭代的方式不同。 1. 高斯赛德尔迭代 高斯赛德尔迭代是按照顺序,每次使用已知的最新的元素来更新未知元素。具体来说,对于 Ax=b 这个线性方程组,高斯赛德尔迭代迭代公式为: $$ x_i^{(k+1)} = \frac{1}{a_{ii}}(b_i - \sum_{j=1}^{i-1}a_{ij}x_j^{(k+1)} - \sum_{j=i+1}^{n}a_{ij}x_j^{(k)}) $$ 其中,$i=1,2,\cdots,n$,$k$ 为迭代次数,$x_i^{(k+1)}$ 表示第 $k+1$ 次迭代后第 $i$ 个未知数的值,$a_{ij}$ 表示矩阵 $A$ 的第 $i$ 行第 $j$ 列元素,$b_i$ 表示向量 $b$ 的第 $i$ 个元素。 高斯赛德尔迭代需要从 $x_i^{(k)}$ 开始迭代,当 $i=1$ 时,使用已知的 $x_2^{(k)},x_3^{(k)},\cdots,x_n^{(k)}$ 来计算 $x_1^{(k+1)}$;当 $i=2$ 时,使用已知的 $x_1^{(k+1)},x_3^{(k)},\cdots,x_n^{(k)}$ 来计算 $x_2^{(k+1)}$;以此类推。 2. 雅克迭代 雅克迭代是同时更新所有未知元素。具体来说,对于 Ax=b 这个线性方程组,雅克迭代迭代公式为: $$ x_i^{(k+1)} = \frac{1}{a_{ii}}(b_i - \sum_{j=1,j\neq i}^{n}a_{ij}x_j^{(k)}) $$ 其中,$i=1,2,\cdots,n$,$k$ 为迭代次数,$x_i^{(k+1)}$ 表示第 $k+1$ 次迭代后第 $i$ 个未知数的值,$a_{ij}$ 表示矩阵 $A$ 的第 $i$ 行第 $j$ 列元素,$b_i$ 表示向量 $b$ 的第 $i$ 个元素。 雅克迭代需要从 $x_i^{(k)}$ 开始迭代,当 $i=1$ 时,使用已知的 $x_1^{(k)},x_2^{(k)},\cdots,x_n^{(k)}$ 来计算 $x_1^{(k+1)}$;当 $i=2$ 时,使用已知的 $x_1^{(k+1)},x_2^{(k)},\cdots,x_n^{(k)}$ 来计算 $x_2^{(k+1)}$;以此类推。 两种方法的主要区别在于更新未知元素的顺序不同。高斯赛德尔迭代每次只更新一个未知元素,但是每次更新后可以马上使用最新的值来更新下一个未知元素,所以收敛速度比较快。而雅克迭代每次更新所有未知元素,但是需要等到所有未知元素的值都更新完毕后才能使用最新的值来更新下一次迭代,所以收敛速度比较慢。但是,雅克迭代可以并行计算,所以适用于多核处理器等并行计算平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值