解線性方程組的直接方法:LU分解法及其C語言算法實現

在上一篇博客裏面,筆者介紹瞭解線性方程組的列主元Guass消元法,這篇將介紹LU分解法及其算法實現.
什麼是LU分解?
對於一個線性方程組Ax=b,其中A是非奇異係數矩陣,b是線性方程組右端項,在列主元Guass消元法裏面我們知道,最後的係數矩陣A將變成一個上三角矩陣,並且是通過一系列的行變換而來的,設最後得到的上三角矩陣爲U,結合高等代數的知識,一個矩陣左乘一個初等矩陣,相當於進行一次行變換,因此設每一次A左乘的初等矩陣爲Li(i=1,2,…,n),則有LnL(n-1)L1A=U,由於Ln均爲初等矩陣,且均爲下三角單位矩陣(因爲每次A進行消元所做的行變換均是從上面的行消去下面的行),所以設L=LnL(n-1)*…*L1,LA=U,A=L-1U,L-1也爲單位下三角矩陣,然後得到了A=LU,我們可以設Ux=y,Ly=b,由於L爲下三角矩陣,求解難度較小,因此通過求解y向量,再由Ux=y求解x,這便是LU分解全部步驟了,對於LU分解矩陣的詳細計算過程,大家可以參考這個網站link
接下來話不多說,上代碼
初始化矩陣

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

進行LU分解

void LU_Position(double**a,int r ,int c)
{
	double num1 = 0,num2=0;
	for (int i=0;i<r;i++)
	{
		if (i==0)//第一行不做處理,單獨算第一列
		{
			for (int j = 1; j < c; j++)
			{
				a[j][i] = a[j][i] / a[0][0];
			}
		}
		else
		{
			for (int j = i; j < c; j++)
			{
				num1 = 0;
				for (int k = 0; k < i; k++)
				{
					num1 += a[i][k] * a[k][j];
				}
				a[i][j] = a[i][j] - num1;
			}
			for (int j = i+1; j < r; j++)
			{
				num2 = 0;
				for (int k = 0; k < i; k++)
				{
					num2 += a[j][k] * a[k][i];
				}
				a[j][i] = (a[j][i] - num2) / a[i][i];
			}
		}
	}
	cout << "所得的LU矩陣爲:" << endl;
	for (int k = 0; k < r; k++)
	{
		for (int n = 0; n < c; n++)
		{
			printf("%f\t", a[k][n]);
		}
		cout << endl;
	}
}

注意:此時我們得到了LU,由於這兩個矩陣均爲稀疏矩陣,且拼接後大小與A矩陣相同,因此我們一直接將計算的兩個矩陣儲存在A矩陣中(A中最後一列爲右端項,不進行處理),這部分計算大家特別要注意的是數組的行列下邊關係
計算y向量及x向量

void calculate(double*y, double*x, double**a,int r)
{
	y[0] = a[0][r];
	double sum=0;
	for (int i = 1; i < r; i++)
	{
		sum = 0;
		for (int k = 0; k < i; k++)
		{
			sum += a[i][k] * y[k];
		}
		y[i] = a[i][r] - sum;
	}
	cout << "所求的向量Y爲:" << endl;
	for (int i = 0; i < r; i++)
	{
		printf("%f\t", y[i]);
	}
	cout << endl;
	for (int i = r-1; i >=0; i--)
	{
		sum = 0;
		for (int j=i+1;j<r;j++)
		{
			sum += a[i][j] * x[j];
		}
		x[i] = (y[i] - sum) / a[i][i];
	}
	cout << "所求線性方程組的解向量X爲:" << endl;
	for (int i = 0; i < r; i++)
	{
		printf("%f\t", x[i]);
	}
	cout << endl;
}

這裏我們將得到的y向量儲存在數組y中
程序完整代碼

#include<iostream>
#include<Windows.h>
using namespace std;
/*
測試數據

2 2
2 3  5
1 -1 0

3 3
3 2 -3 -2
1 1  1  6
1 2 -1  2

3 3
1  2 -3 1
2 -1  3 5
3 -2  2 1

4 4
4 -3  6  7 11
1  1  3  4 10
-2 9 -7  1 10
3  3 -4 20 25

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;
}
//直接用A來儲存LU和方程組右邊的常數項 進行LU分解時 右邊常數項不做處理 即最後一列全部不處理
void LU_Position(double**a,int r ,int c)
{
	double num1 = 0,num2=0;
	for (int i=0;i<r;i++)
	{
		if (i==0)
		{
			for (int j = 1; j < c; j++)
			{
				a[j][i] = a[j][i] / a[0][0];
			}
		}
		else
		{
			for (int j = i; j < c; j++)
			{
				num1 = 0;
				for (int k = 0; k < i; k++)
				{
					num1 += a[i][k] * a[k][j];
				}
				a[i][j] = a[i][j] - num1;
			}
			for (int j = i+1; j < r; j++)
			{
				num2 = 0;
				for (int k = 0; k < i; k++)
				{
					num2 += a[j][k] * a[k][i];
				}
				a[j][i] = (a[j][i] - num2) / a[i][i];
			}
		}
	}
	cout << "所得的LU矩陣爲:" << endl;
	for (int k = 0; k < r; k++)
	{
		for (int n = 0; n < c; n++)
		{
			printf("%f\t", a[k][n]);
		}
		cout << endl;
	}
}
void calculate(double*y, double*x, double**a,int r)
{
	y[0] = a[0][r];
	double sum=0;
	for (int i = 1; i < r; i++)
	{
		sum = 0;
		for (int k = 0; k < i; k++)
		{
			sum += a[i][k] * y[k];
		}
		y[i] = a[i][r] - sum;
	}
	cout << "所求的向量Y爲:" << endl;
	for (int i = 0; i < r; i++)
	{
		printf("%f\t", y[i]);
	}
	cout << endl;
	for (int i = r-1; i >=0; i--)
	{
		sum = 0;
		for (int j=i+1;j<r;j++)
		{
			sum += a[i][j] * x[j];
		}
		x[i] = (y[i] - sum) / a[i][i];
	}
	cout << "所求線性方程組的解向量X爲:" << endl;
	for (int i = 0; i < r; i++)
	{
		printf("%f\t", x[i]);
	}
	cout << endl;
}
void LU_position_main() {
	cout << "輸入矩陣的行列:" << endl;
	int i = 0, j = 0;
	cin >> i >> j;
	double** p = init_Matrix(i, j);
	LU_Position(p, i, j);
	double* a = new double[i];
	memset(a, 0, sizeof(double) * i);
	double* b = new double[i];
	memset(b, 0, sizeof(double) * i);
	calculate(a, b, p, i);
	delete[]a;
	delete[]b;
	for (int i = 0; i < j; i++)
	{
		delete[]p[i];
	}
	delete[]p;
}
int main(void) {
	LU_position_main();
	system("pause");
	return 0;
}

歡迎交流探討~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章