上篇給大家講解了迭代法中的Jacobi迭代法,這篇將給大家講解一個收斂更快的方法:Guass-Seidel迭代法,在方法上,Guass-Seidel迭代法和Jacobi迭代法大同小異,它的迭代式與Jacobi迭代法的差不多,唯一的差別就是,在Jacobi迭代法中,我們是按照順序依次求
X1k+1,X2k+1,…,Xnk+1,即每個分量都由前一次迭代的Xik計算得到,而在這個過程中,我們求Xnk+1時,前面的n-1項都已經求出來了,我們就可以將其替換成Xik+1(i<n)而後面i>n的部分,就按照前一次迭代的結果來計算,由於有了Jacobi迭代法的基礎,這裏就直接看代碼實現
初始化
double** init_Matrix(int r, int c)
{
double** p = new double* [r];
int d = c + 1;
for (int i = 0; i < r; i++)
{
p[i] = new double[d];
memset(p[i], 0, sizeof(double) * d);
}
cout << "請輸入線性方程組對應的增廣矩陣:" << endl;
for (int i = 0; i < r; i++)
{
for (int j = 0; j < d; j++)
{
cin >> p[i][j];
}
}
return p;
}
判斷精度
bool isRight(double** p, int r, double* x)
{
double sum1 = 0, flag = 0, sum2 = 0;
for (int i = 0; i < r; i++)
{
sum1 = 0, flag = 0;
for (int j = 0; j < r; j++)
{
sum1 += x[j] * p[i][j];
}
flag = fabs(p[i][r] - sum1);
if (flag > (1e-5))//解代入單個方程式的誤差過大
{
return false;
}
else
{
sum2 += flag;
}
}
if (sum2 > (3e-5))//整體誤差過大
{
return false;
}
return true;
}
作用與Jacobi迭代法相同
迭代計算
void Iteration(double** p, int r, double* x)
{
int k = 0, max_time = 300;//最大迭代次數
double sum = 0;
while (true)
{
for (int i = 0; i < r; i++)
{
sum = 0;
for (int j = 0; j < r; j++)
{
if (j == i)
{
continue;
}
else
{
sum -= p[i][j] * x[j];
}
}
x[i] = (p[i][r] + sum) / p[i][i];
}
printf("第%d次迭代結果爲:", ++k);
for (int i = 0; i < r; i++)
{
printf("%f\t", x[i]);
}
cout << endl;
if (k >= max_time)
{
cout << "超出迭代次數上限!停止迭代" << endl;
return;
}
if (isRight(p, r, x))//精度符合要求
{
cout << "精度符合要求,停止迭代,共迭代:" << k << "次" << endl;
return;
}
}
}
這裏與Jacobi迭代法不同的地方就是,不需要存儲上一次的運算結果,直接用每個解分量之前的解分量去求,未知的部分就用上一次的迭代結果
綜合運用
void Gauss_seidel_main()
{
int i = 0, j = 0;
cout << "請輸入線性方程組對應係數矩陣的行和列:" << endl;
cin >> i >> j;
double** p = init_Matrix(i, j);
double* X = new double[i];//第n+1次跌代
memset(X, 0, sizeof(double) * i);
Iteration(p, i, X);
for (int i = 0; i < j; i++)
{
delete[]p[i];
}
delete[]p;
delete[]X;
}
同樣別忘記了,釋放內存,防止內存泄漏
完整代碼及測試數據
#include<iostream>
#include<Windows.h>
#include<string>
using namespace std;
/*
測試數據
3 3
10 -1 0 9
-1 10 -2 7
0 -2 10 6
3 3
20 -1 2 74
2 8 1 -4
1 -2 4 56
3 3
8 -3 2 20
4 11 -1 33
2 1 4 12
5 5
28 -3 0 0 0 10
-3 38 -10 0 -5 0
0 -10 25 -15 0 0
0 0 -15 45 0 0
0 -5 0 0 30 0
*/
double** init_Matrix(int r, int c)
{
double** p = new double* [r];
int d = c + 1;
for (int i = 0; i < r; i++)
{
p[i] = new double[d];
memset(p[i], 0, sizeof(double) * d);
}
cout << "請輸入線性方程組對應的增廣矩陣:" << endl;
for (int i = 0; i < r; i++)
{
for (int j = 0; j < d; j++)
{
cin >> p[i][j];
}
}
return p;
}
bool isRight(double** p, int r, double* x)
{
double sum1 = 0, flag = 0, sum2 = 0;
for (int i = 0; i < r; i++)
{
sum1 = 0, flag = 0;
for (int j = 0; j < r; j++)
{
sum1 += x[j] * p[i][j];
}
flag = fabs(p[i][r] - sum1);
if (flag > (1e-5))//解代入單個方程式的誤差過大
{
return false;
}
else
{
sum2 += flag;
}
}
if (sum2 > (3e-5))//整體誤差過大
{
return false;
}
return true;
}
//用一維數組x存儲每次迭代的解向量
void Iteration(double** p, int r, double* x)
{
int k = 0, max_time = 300;//最大迭代次數
double sum = 0;
while (true)
{
for (int i = 0; i < r; i++)
{
sum = 0;
for (int j = 0; j < r; j++)
{
if (j == i)
{
continue;
}
else
{
sum -= p[i][j] * x[j];
}
}
x[i] = (p[i][r] + sum) / p[i][i];
}
printf("第%d次迭代結果爲:", ++k);
for (int i = 0; i < r; i++)
{
printf("%f\t", x[i]);
}
cout << endl;
if (k >= max_time)
{
cout << "超出迭代次數上限!停止迭代" << endl;
return;
}
if (isRight(p, r, x))//精度符合要求
{
cout << "精度符合要求,停止迭代,共迭代:" << k << "次" << endl;
return;
}
}
}
void Gauss_seidel_main()
{
int i = 0, j = 0;
cout << "請輸入線性方程組對應係數矩陣的行和列:" << endl;
cin >> i >> j;
double** p = init_Matrix(i, j);
double* X = new double[i];//第n+1次跌代
memset(X, 0, sizeof(double) * i);
Iteration(p, i, X);
for (int i = 0; i < j; i++)
{
delete[]p[i];
}
delete[]p;
delete[]X;
}
int main(void)
{
Gauss_seidel_main();
system("pause");
return 0;
}