[线性代数]矩阵求逆

版权声明:转载请说明Zhonglihao原创 https://blog.csdn.net/xeonmm1/article/details/88084466
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h> 
#include "stdio.h"

void MatrixPrint(double* arr, const int row, const int col);
double* MatrixInverse(double* arr_in, const int n);
void MatrixPivotExchange(double* arr, double* arr_inv, const int n, const int row);

int _tmain(int argc, _TCHAR* argv[])
{   
	//统一使用一维数组实现
	const int row_A = 3;
	const int col_A = 3;
	double Mat_A[row_A*col_A] = { 1, 1, 1, 6, 3, 2, 3, 4, 3 };

	//计算逆阵
	double *Mat_A_Inv = MatrixInverse(Mat_A, row_A);

	//打印原始矩阵和逆阵
	MatrixPrint(Mat_A, row_A, col_A);
	MatrixPrint(Mat_A_Inv, row_A, col_A);

	system("Pause");
	return 0;
}

double* MatrixInverse(double* arr_in, const int n)
{
	int len = n * n;
	int i;
	int col_scan, row_scan, resi_row_scan;	//主行扫描 余行消除主元扫描
	double pivot;							//主元缓存
	
	//复制一份拷贝以防止改变原有数组
	double *arr = (double *)malloc(len * sizeof(double));
	for (i = 0; i < len; i++) arr[i] = arr_in[i];

	//申请内存 置0 对角线置1
	double *arr_inv = (double *)malloc(len * sizeof(double));
	if (arr_inv == NULL) return NULL;

	for (i = 0; i < len; i++)
	{
		if ((int)(i / n) == (int)(i % n))
			arr_inv[i] = 1;
		else
			arr_inv[i] = 0;
	}

	//开始计算逆阵
	for (row_scan = 0; row_scan < n; row_scan++)
	{
		//列主元换位
		MatrixPivotExchange(arr, arr_inv, n, row_scan);

		//原矩阵与增广矩阵行元素均需要除以列主元
		pivot = arr[row_scan * (n + 1)];

		for (col_scan = row_scan; col_scan < n; col_scan++) // 下三角
		{
			arr[row_scan * n + col_scan] = arr[row_scan * n + col_scan] / pivot;
		}

		for (col_scan = 0; col_scan < n; col_scan++) //逆阵区全部都要计算
		{
			arr_inv[row_scan * n + col_scan] = arr_inv[row_scan * n + col_scan] / pivot;
		}

		//通过主元行消除其余行首位元素
		for (resi_row_scan = row_scan + 1; resi_row_scan < n; resi_row_scan++)
		{
			pivot = arr[resi_row_scan * n + row_scan];

			for (col_scan = row_scan; col_scan < n; col_scan++) //下三角
			{
				arr[resi_row_scan * n + col_scan] = arr[resi_row_scan * n + col_scan] - pivot * arr[row_scan * n + col_scan];
			}

			for (col_scan = 0; col_scan < n; col_scan++) //逆阵区全部都要计算
			{
				arr_inv[resi_row_scan * n + col_scan] = arr_inv[resi_row_scan * n + col_scan] - pivot * arr_inv[row_scan * n + col_scan];
			}
		}
	}

	//反三角往上消除
	for (row_scan = n - 1; row_scan >= 0; row_scan--)
	{
		for (resi_row_scan = row_scan - 1; resi_row_scan >= 0; resi_row_scan--)
		{
			pivot = arr[resi_row_scan * n + row_scan];
			arr[resi_row_scan * n + row_scan] = 0;

			for (col_scan = 0; col_scan < n; col_scan++) //逆阵区全部都要计算
			{
				arr_inv[resi_row_scan * n + col_scan] = arr_inv[resi_row_scan * n + col_scan] - pivot * arr_inv[row_scan * n + col_scan];
			}
		}
	}

	free(arr);
	return arr_inv;
}

//列主元换位
void MatrixPivotExchange(double* arr, double* arr_inv, const int n, const int row) //row为现在处理的行
{
	int    row_scan, col_scan;						//循环标记
	int	   col				= row;					//列主元的扫描列 就是输入的行
	double max_value		= arr[row * (n + 1)];	//输入时行的列主元值
	int	   max_value_row	= row;					//记录最大列主元的所在行
	double cmp_calue		= 0;
	double temp				= 0;

	int org_index, max_index;

	//找到列主元的最大值所在行
	for (row_scan = row + 1; row_scan < n; row_scan++)
	{
		cmp_calue = arr[row_scan * n + col];
		if (max_value < cmp_calue)
		{
			max_value	  = cmp_calue;
			max_value_row = row_scan;
		}
	}

	//原矩阵与逆阵均需要换行
	if (row != max_value_row)
	{
		for (col_scan = 0; col_scan < n; col_scan++)
		{
			org_index = row * n + col_scan;
			max_index = max_value_row * n + col_scan;

			temp = arr[org_index];
			arr[org_index] = arr[max_index];
			arr[max_index] = temp;

			//兼容单矩阵和逆阵
			if (arr_inv != NULL)
			{
				temp = arr_inv[org_index];
				arr_inv[org_index] = arr_inv[max_index];
				arr_inv[max_index] = temp;
			}
		}
	}
	
	return;
}


//矩阵打印方法
void MatrixPrint(double* arr, const int row, const int col)
{
	int len = row * col;
	int i,col_count;

	for (i = 0, col_count = 0; i < len; i++)
	{
		printf("%f\t", arr[i]);

		//单换行
		if (++col_count >= col)
		{
			printf("\n");
			col_count = 0;
		}
	}

	//跳空换行
	printf("\n");

	return;
}

猜你喜欢

转载自blog.csdn.net/xeonmm1/article/details/88084466
今日推荐