c++矩阵求逆的lu分解实现

c++矩阵求逆的lu分解实现

初学c++,尝试利用基础知识编写矩阵求逆。但发现求解伴随阵的过程非常复杂且难以实现,而我正好看到一篇求三角阵伴随矩阵的文章,故尝试编程实现。在这种方法下,计算量明显减小,实现方法,思路适合初学者。

参考文献:三角形矩阵求伴随矩阵的一种方法(曾月新)

求逆矩阵思路:
1.求矩阵的crout(LU)分解,其中L为下三角矩阵,U为上三角矩阵
2.求L,U矩阵的伴随阵,见参考文献
3.求L,U矩阵的逆(伴随阵A* /det(A))
4.inv_A = inv_U * inv_L

附上代码如下:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

const int n=3;//逆矩阵阶数,求不同阶数矩阵请修改n的值
int main()
{
	double a[n][n],inv_a[n][n];
	memset(a, 0, n * n * sizeof(double));
	printf("Please input the %dX%d matrix A:\n",n,n);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin>>a[i][j];
		}
	}
	void out(double matrix[][n], const char* s);
	void product(double matrix1[][n], double matrix2[][n], double matrix_result[n][n]);
	//初始化
	double l[n][n], u[n][n], c[n][n], ad_l[n][n], ad_u[n][n];
	memset(inv_a, 0, n * n * sizeof(double));
	memset(l, 0, n * n * sizeof(double));
	memset(u, 0, n * n * sizeof(double));
	memset(c, 0, n * n * sizeof(double));
	memset(ad_l, 0, n * n * sizeof(double));
	memset(ad_u, 0, n * n * sizeof(double));
	

	//LU分解
	for (int i = 0; i < n; i++)
		l[i][i] = 1;
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = i; j < n; j++)
		{
			double tem = 0;
			for (int k = 0; k < i; k++)
				tem += l[i][k] * u[k][j];
			u[i][j] = a[i][j] - tem;
		}
		for (int j = i + 1; j < n; j++)
		{
			double tem = 0;
			for (int k = 0; k < i; k++)
				tem += l[j][k] * u[k][i];
			l[j][i] = (a[j][i] - tem) / u[i][i];
		}
	}
	u[n - 1][n - 1] = a[n - 1][n - 1];
	for (int i = 0; i < n - 1; i++)
		u[n - 1][n - 1] -= l[n - 1][i] * u[i][n - 1];
	//矩阵L
	//out(l, "矩阵L");
	//矩阵U
	//out(u, "矩阵U");
	//L*U
	//product(l,u, c);
	//out(c, "矩阵L*U");


	//U的逆矩阵
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (i > j) ad_u[i][j] = 0;
			else if (i == j)
			{
				ad_u[i][j] = 1;
				for (int k = 0; k < n; k++)
					if (k != j)
						ad_u[i][j] *= u[k][k];
			}
			else if (j - i == 1)
			{
				ad_u[i][j] = -u[i][j];
				for (int k = 0; k < n; k++)
					if (k != i && k != j)
						ad_u[i][j] *= u[k][k];
			}
			else if (j - i >= 2)
			{
				double deltas_aii = 1;
				for (int k = 0; k < n; k++)
					if (k < i || k > j)
						deltas_aii *= u[k][k];
				int permutation[n];
				for (int t = 0; t < j - i; t++) permutation[t] = i + t + 1;
				double sum = 0;
				do
				{
					int cnt = 0;
					for (int t2 = 0; t2 < j - i; t2++)
						for (int t3 = t2; t3 < j - i; t3++)
							if (permutation[t3] < permutation[t2]) cnt++;
					double mul = 1;
					for (int t1 = i; t1 < j; t1++)
                        mul *= u[t1][permutation[t1 - i]];
					if ((j - i + 1) % 2 == 0)mul *= -1;
					if (cnt % 2 == 0) sum += mul;
					else sum -= mul;
				} while (next_permutation(permutation, permutation + j - i));
				ad_u[i][j] = sum * deltas_aii;
			}
		}
	}
	double det_u = 1;
	for (int k = 0; k < n; k++) det_u *= u[k][k];
	if (det_u < 1e-16)
	{
		printf("矩阵不可逆,请检查输入!\n");
		return 0;
	}
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			ad_u[i][j] /= det_u;
	//inv_U
	//out(ad_u, "inv_U");
	//U*U-1
	//memset(c, 0, n*n * sizeof(double));
	//product(u, ad_u, c);
	//out(c, "矩阵U*U-1");


	//l的逆矩阵
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (i < j) ad_l[i][j] = 0;
			else if (i == j)
			{
				ad_l[i][j] = 1;
				for (int k = 0; k < n; k++)
					if (k != j)
						ad_l[i][j] *= l[k][k];
			}
			else if (i - j == 1)
			{
				ad_l[i][j] = -l[i][j];
				for (int k = 0; k < n; k++)
					if (k != i && k != j)
						ad_l[i][j] *= l[k][k];
			}
			else if (i - j >= 2)
			{
				double deltas_aii = 1;
				for (int k = 0; k < n; k++)
					if (k < i || k > j)
						deltas_aii *= l[i][i];
				int permutation[n];
				for (int t = 0; t < i - j; t++) permutation[t] = j + t + 1;
				double sum = 0;
				do
				{
					int cnt = 0;
					for (int t2 = 0; t2 < i - j; t2++)
						for (int t3 = t2; t3 < i - j; t3++)
							if (permutation[t3] < permutation[t2]) cnt++;
					double mul = 1;
					for (int t1 = j; t1 < i; t1++) 
                        mul *= l[permutation[t1 - j]][t1];
					if ((i - j + 1) % 2 == 0)mul *= -1;
					if (cnt % 2 == 0) sum += mul;
					else sum -= mul;
				} while (next_permutation(permutation, permutation + i - j));
				ad_l[i][j] = sum * deltas_aii;
			}
		}
	}
	double det_l = 1;
	for (int k = 0; k < n; k++) det_l *= l[k][k];
	if (det_u < 1e-16)
	{
		printf("矩阵不可逆,请检查输入!\n");
		return 0;
	}
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			ad_l[i][j] /= det_l;
	//矩阵inv_L
	//out(ad_l, "矩阵inv_L=");
	//L*L-1
	//memset(c, 0, n*n * sizeof(double));
	//product(l, ad_l, c);
	//out(c, "矩阵L*inv_L=");


	//矩阵a
	out(a, "矩阵a=");
	//inv_a
	product(ad_u, ad_l, inv_a);
	out(inv_a, "逆矩阵inv_a=");

	//验证a*inv_a
	memset(c, 0, n * n * sizeof(double));
	product(a, inv_a, c);
	out(c, "矩阵a*inv_a=");

	system("pause");
	return 0;
	
}




void out(double matrix[][n], const char* s)
{
	cout << s << endl;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
			fabs(*(*(matrix + i) + j))<1e-10? cout << 0 << '\t':cout << *(*(matrix + i) + j) << '\t';
		cout << endl;
	}
	cout << endl;
}

void product(double matrix1[n][n], double matrix2[n][n], double matrix_result[n][n])
{
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			for (int k = 0; k < n; k++)
				matrix_result[i][j] += matrix1[i][k] * matrix2[k][j];
}
  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
矩阵求逆LU分解是一种求解矩阵逆的算法,通过将矩阵分解为下三角矩阵L和上三角矩阵U的积,然后利用这两个矩阵求解矩阵的逆。 首先,我们需要将矩阵A进行LU分解,得到下三角矩阵L和上三角矩阵U。具体步骤如下: 1. 初始化L为单位下三角矩阵,即L的对角线元素全为1,U为矩阵A的副本。 2. 对于矩阵U的每一列,我们将其第一行元素记为U[1, j],然后计算L的第一列元素L[i, 1](i = 2, 3, ..., n)以及矩阵U的第i行元素U[i, j](i = 2, 3, ..., n): - L[i, 1] = U[i, 1] / U[1, 1] - U[i, j] = U[i, j] - L[i, 1] * U[1, j] 3. 对于矩阵U的第二列至第n列,我们依次计算L的第一行至第n-1行元素以及矩阵U的第i行元素(i = 2, 3, ..., n): - L[i, k] = (U[i, k] - sum(L[i, j] * U[j, k] for j in range(1, k))) / U[k, k] - U[i, j] = U[i, j] - sum(L[i, k] * U[k, j] for k in range(1, j)) 得到矩阵L和矩阵U后,我们可以按照以下步骤计算矩阵的逆: 1. 初始化矩阵I为单位矩阵。 2. 对于每一列的矩阵I的列向量b,利用L和U解出方程Ax = b,即x = U^(-1)L^(-1)b。 3. 将得到的每一列向量x按列组合起来得到矩阵的逆。 需要注意的是,在实际计算中,如果遇到U的对角线元素接近或者等于0的情况,则矩阵不存在逆,因此需要避免这种情况的发生。同时,如果矩阵A是一个稀疏矩阵,那么LU分解可能不是最优的求解方法,可以考虑使用其他方法求解矩阵逆。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值