求解非齐次线性方程组算法

1.      非齐次线性方程组有解的条件

如下非齐次线性方程组:


由系数矩阵和常数列向量构成的增广矩阵如下:


无解情况:


唯一解情况:


无穷解情况:

 

2.      高斯消元法求解

步骤:

1)    消元法

通过矩阵的初等变换,将增广矩阵变换为上三角矩阵


2)    回代法

采用回代法求解上三角矩阵对应的非齐次线性方程组,即从第n个方程开始求解,解出


然后再将解出之代入第n-1个方程解出,…,直到解出所有来。

       注意到在消元和回代的过程中均需使用矩阵A的主对角线元素(称为主元素)作除数,因此如果原方程组的某个主对角线元素等于0,就会导致求解失败。而且从数值计算的特点可知,即使某个主元素并未等于0,而只是其绝对值很小,也会导致较大的计算误差。因此,我们可以通过调换方程组中某些方程的相对位置来保证主对角线上的元素取较大的绝对值,这就是列主元素法。

 

3.     算法实现

考虑简单的情况,求解如下:


方程。


C语言代码:

/*
*
* Copyright (c) 2011,武汉大学国家多媒体中心
* All rights reserved.
*
* 文件名称:SolutionLinearEquation.cpp
* 摘要:列主元素高斯消元法解n元一次方程组
*
* 当前版本:1.0
* 作者:王汪
* 完成日期:2011年9月10日
*
*/

#include 
#include 

/*
 * 功能:选取列主元素
 * 输入:A[]		系数矩阵A;
 *		B[]		常数列向量B;
 *		A_Rows	系数矩阵A的行数;
 *		Kst_Row	待求的第k行列主元素
 * 输出:void
 */
void ColumnPrimaryElement(double A[], double B[], int A_Rows, int Kst_Row)
{
	// 用于存放列主元素的值
	double main_element = 0.0;
	// 用于存放列主元素所在行
	int main_line = 0;

	// 中间变量,用于交换
	double temp = 0.0;
	// 循环变量
	int i, j;

	// 暂定A[k, k]为列主元素
	main_element = A[Kst_Row * A_Rows + Kst_Row];
	main_line = Kst_Row;

	for (i = Kst_Row + 1; i < A_Rows; ++i)
	{
		if (fabs(A[i * A_Rows + Kst_Row]) > fabs(main_element))
		{
			main_element = A[i * A_Rows + Kst_Row];
			main_line = i;
		}

		// 如果第k列元素中绝对值最大的不是a[k,k],则交换两个方程
		if (main_line != Kst_Row)
		{
			for (j = Kst_Row; j < A_Rows; ++j)
			{
				temp = A[Kst_Row * A_Rows + j];
				A[Kst_Row * A_Rows + j] = A[main_line * A_Rows + j];
				A[main_line * A_Rows + j] = temp;
			}

			temp = B[Kst_Row];
			B[Kst_Row] = B[main_line];
			B[main_line] = temp;
		}
	}
}

/*
 * 功能:列主元素高斯消元法解n元一次方程组
 * 输入:A[]		系数矩阵A;
 *		B[]		常数列向量B;
 *		A_Rows	系数矩阵A的行数;
 * 输出:X[]		结果向量
 */

void Gauss_ColumnPrimaryElement(double A[], double B[], int A_Rows, double X[])
{
	// 循环变量
	int i, j, k;
	// 高斯消元比例因子
	double c;

	// 消元
	for (k = 0; k < A_Rows; ++k)
	{
		// 选取列主元素
		ColumnPrimaryElement(A, B, A_Rows, k);
		for (i = k + 1; i < A_Rows; ++i)
		{
			// 求得高斯消元比例因子
			c = A[i * A_Rows + k] / A[k * A_Rows + k];

			for (j = k + 1; j < A_Rows; ++j)
			{
				A[i * A_Rows + j] = A[i * A_Rows + j] - A[k * A_Rows + j] * c;
			}
			B[i] = B[i] - B[k] * c; 
		}
	}

	// 有解条件判断
	// 系数矩阵A的秩等于A的维数n(即行数或者列数)
	if (fabs(A[(A_Rows - 1) * A_Rows + (A_Rows - 1)]) < 10e-6)
	{
		// 不存在唯一解
		printf("不存在唯一解!\n");

		for (i = 0; i < A_Rows; ++i)
		{
			X[i] = 0.0;
		}
		return;
	}

	// 回代求解
	for (i = A_Rows -1; i >= 0; --i)
	{
		X[i] = B[i];
		for (j = i + 1; j < A_Rows; ++j)
		{
			X[i] = X[i] - A[i * A_Rows + j] * X[j];
		}
		X[i] = X[i] / A[i * A_Rows + i];
	}
}

void main()
{
	double A[4][4] = 
	{
		{0.2368, 0.2471, 0.2568, 1.2671},
		{0.1968, 0.2071, 1.2168, 0.2271},
		{0.1581, 1.1675, 0.1768, 0.1871},
		{1.1161, 0.1254, 0.1397, 0.1490},
	};

	double B[4] = 
	{
		1.8471, 1.7471, 1.6471, 1.5471
	};

	double X[4];

	int i = 0;

	Gauss_ColumnPrimaryElement(A[0], B, 4, X);

	printf("The result is x = \n");
	for (i = 0; i < 4; ++i)
	{
		printf("%10.6lf\n", X[i]);
	}
}

// MATLAB测试
// A = [[0.2368, 0.2471, 0.2568, 1.2671];[0.1968, 0.2071, 1.2168, 0.2271];[0.1581, 1.1675, 0.1768, 0.1871];[1.1161, 0.1254, 0.1397, 0.1490]]
// B = [1.8471; 1.7471; 1.6471; 1.5471]
// A \ B


你可能感兴趣的:(数据结构与算法分析)