/************************************************************************/
/*
矩阵是否可逆是利用矩阵的行列式是否为0来进行判定的
如果为0 则不可逆, 否则可逆
对于可逆矩阵的逆矩阵运算可以通过这两种方式来计算
1、迭代运算, 既行列式按行展开法
2、高斯消元来获得上三角或下三角(在一些资料中我们会发现高斯消元的过程中, 防止出现Mat[i][j]=0, 造成无法消除i+1...n行的j列元素, 从而执行找右下角最大元素来交换的方式, 也就是主元...的)
前几天正好帮一个人写了一些矩阵的东西, 感觉能在你这边用上, 所以写给你了
*/
/************************************************************************/
#include
#include
#include
#include
// 矩阵的内存分配、初始化、显示和释放
double ** mallocMat(const int m, const int n); // 为n维矩阵分配空间
void initMat(double ** Mat, const int n); // 利用随机数填充n维矩阵Mat
void showMat(char * pstr, double ** Mat, const int m, const int n); // 显示n维Mat矩阵的元素
void freeMem(double ** Mat, const int n); // 进行内存释放
// 这些函数是实现我们平常用的主元高斯消元来求解矩阵的行列式的
double detOfMat(double ** Mat, const int n);
double adjustK(double ** Mat, const int n, const int k);
void swap(double * a, double * b);
double guiyi(double ** Mat, const int n, const int k);
void xiaoyuan(double ** Mat, const int n, const int k);
void copyMat(double ** MatA, double ** MatB, const int n);
// 求解逆矩阵
void getPlus(double ** MatOri, double ** MatRes, const int n);
void getInv(double ** MatPlus, double ** MatInv, const int n);
int main(void)
{
unsigned int n=0;
printf("请输入矩阵的维数n:");
double ** MatOri;
double ** MatPlus;
double ** MatInv;
while (scanf("%d", &n))
{
MatOri = mallocMat(n, n);
initMat(MatOri, n);
showMat("原始矩阵为:", MatOri, n, n);
double det = 0.0;
det = detOfMat(MatOri, n);
printf("det(MatOri) = %5.2lf\n", det);
if ((int)det != 0)
{
MatPlus = mallocMat(n, 2*n);
MatInv = mallocMat(n, n);
getPlus(MatOri, MatPlus, n);
getInv(MatPlus, MatInv, n);
// showMat("增广矩阵:", MatPlus, n, 2*n);
showMat("逆矩阵为:", MatInv, n, n);
freeMem(MatPlus, n);
freeMem(MatInv, n);
}
freeMem(MatOri, n);
printf("\n请输入矩阵的维数n:");
}
return 0;
}
/************************************************************************/
/*
功能: 在堆上分配一个m*n的矩阵空间, 并将所分配的内存初始化为0
输入: m: 矩阵的行大小
n:矩阵的列大小
输出: 返回分配的内存的首地址
*/
/************************************************************************/
double ** mallocMat(const int m, const int n)
{
double ** rtnPHead = (double **)malloc(sizeof(double *) * m);
for (int i=0; i
*(rtnPHead+i) = (double *)malloc(sizeof(double) * n);
}
for (i=0; i
for (int j=0; j
rtnPHead[i][j] = 0;
}
}
return rtnPHead;
}
/************************************************************************/
/*
功能: 对矩阵n维矩阵Mat进行赋值操作
输入: Mat: 要进行填充的矩阵
n: 矩阵的维数
输出: 空
*/
/************************************************************************/
void initMat(double ** Mat, const int n)
{
srand((unsigned)time(NULL));
int flag = 0;
while (flag!=1 && flag!=2)
{
printf("1、手动输入, 2、利用随机数填充\n");
scanf("%d", &flag);
}
if (flag ==1)
{
for (int i=0; i
printf("请输入第 %d 行数据, 中间以空格隔开\n", i+1);
for (int j=0; j
scanf("%lf", &Mat[i][j]);
}
}
}
else
{
for (int i=0; i
for (int j=0; j
Mat[i][j] = rand()%(10); // 将随机数控制在0-49
}
}
}
return;
}
/************************************************************************/
/*
功能: 显示矩阵元素
输入: pstr:提示信息
Mat:二维矩阵首元素地址
n: 矩阵的维数
输出: void
*/
/************************************************************************/
void showMat(char * pstr, double **Mat, const int m, const int n)
{
printf(pstr);
printf("\n");
for (int i=0; i
for (int j=0; j
printf("\t%5.2f ", Mat[i][j]);
}
printf("\n");
}
return;
}
/************************************************************************/
/*
功能: 将矩阵matA复制到矩阵matB
输入: matA:被复制矩阵
matB:接受复制的矩阵
n:二维矩阵的维数
输出: void
*/
/************************************************************************/
void copyMat(double **matA, double **matB, const int n)
{
for (int i=0; i
for (int j=0; j
matB[i][j] = matA[i][j];
}
}
return;
}
/************************************************************************/
/*
功能: 求解矩阵行列式(一定注意这里面做了一个矩阵拷贝来实现det的求解的, 否则后面的Mat矩阵使用就会出现问题)
输入: Mat:带求解矩阵
n:矩阵的维数
flg:标识是否可逆
输出: 矩阵的行列式
*/
/************************************************************************/
double detOfMat(double **oriMat, const int n)
{
double ** Mat = mallocMat(n, n);
copyMat(oriMat, Mat, n);
double res = 1.0, valKKOfMat = 0;
for (int k=0; k
valKKOfMat = adjustK(Mat, n, k);
if (valKKOfMat == 0)
{
res = 0;
break;
}
guiyi(Mat, n, k);
xiaoyuan(Mat, n, k);
res *= valKKOfMat;
}
freeMem(Mat, n);
return res;
}
/************************************************************************/
/*
功能: 调整矩阵, 使得Mat[k][k]的绝对值是for(i = k..n){for(j = k...n)}中最大的
输入: Mat:要调整的矩阵
n:矩阵的维数
k:位置下标
输出: Mat[k][k]处的值与交换后的系数之积(交换偶数次系数是1, 交换奇数次是-1)
*/
/************************************************************************/
double adjustK(double **Mat, const int n, const int k)
{
// 获取右下角余矩阵的最大绝对值位置
int XofMax = k, YofMax = k;
double Max = Mat[k][k];
int icnt = 1;
for (int i=k; i
for (int j=k; j
if ((int)(fabs(Mat[i][j])*10+0.5) > (int)(Max*10+0.5))
{
XofMax = i;
YofMax = j;
}
}
}
// 进行行变换
if (XofMax != k)
{
icnt *= -1;
for (int i=0; i
swap(&Mat[XofMax][i], &Mat[k][i]);
}
}
// 进行列变换
if (YofMax != k)
{
for (int i=0; i
swap(&Mat[i][YofMax], &Mat[i][k]);
}
icnt *= -1;
}
return icnt*Mat[k][k];
}
/************************************************************************/
/*
功能: 完成两个数据的数值交换
输入: a:第一个元素的地址
b:第二个元素的地址
输出: void
*/
/************************************************************************/
void swap(double * a, double * b)
{
double tmp = *a;
*a = *b;
*b = tmp;
return;
}
/************************************************************************/
/*
功能: 将Mat矩阵的k行的元素都除以Mat[k][k]
输入: Mat:二维矩阵
n:二维矩阵的维数
k:要执行的列号
输出: Mat[k][k]的值(double)
*/
/************************************************************************/
double guiyi(double **Mat, const int n, const int k)
{
double rtndobl = Mat[k][k];
for (int j=k; j
Mat[k][j] = Mat[k][j]/rtndobl;
}
return rtndobl;
}
/************************************************************************/
/*
功能: 根据Mat[k][k]处的值将Mat[k+1...n][k]全都变为0
输入: Mat:二维矩阵
n:二维矩阵的维数
k:要执行的列号
输出: Mat[k][k]的值(double)
*/
/************************************************************************/
void xiaoyuan(double ** Mat, const int n, const int k)
{
double * lieEle = (double *)malloc(sizeof(double) * (n-k-1));
for (int index=0; index<(n-k-1); index++)
{
lieEle[index] = Mat[k+1+index][k];
}
double tmp = 0.0;
for (int i=k+1; i
for (int j=k; j
Mat[i][j] = Mat[i][j] - lieEle[i-k-1]*Mat[k][j];
tmp = Mat[i][j];
}
}
free(lieEle);
return;
}
/************************************************************************/
/*
功能: 利用伴随矩阵获得逆矩阵
输入: matA:待求逆矩阵
matB:伴随矩阵
N:矩阵的行数
输出: void
*/
/************************************************************************/
void getPlus(double ** matA, double ** matB, const int N)
{
double t;
int i=0, j=0;
// 首先将matA的元素拷贝到MatB的左半侧
for(i=0;i
// 对右半侧形成单位阵
for(i=0;i
matB[i][j]=0;
for(i=0;i
// showMat("ori->:", matB, N, 2*N);
// 形成增广矩阵左侧上三角的过程
for(int m=0; m
t=matB[m][m]; //预存matB[m][m]。
i=m;
// 防止matB[m][m]是0, 这样就不好做下面的消元, 所以这里是查找下面不是0的元素
while(matB[m][m]==0 && i+1
matB[m][m]=matB[i+1][m];
i++;
}
// 判断是否要进行交换, 如果前面的i变大则说明要交换,i记录的是要交换的行号
if(i>m)
{
matB[i][m]=t; //实现交换。
//交换其它各列相应位置的元素
for(j=0; j<2*N; j++)
{
t=matB[m][j];
matB[m][j]=matB[i][j];
matB[i][j]=t;
}
// 右侧元素相应的做交换
// for(j=m+1; j<2*N; j++)
// {
// t=matB[m][j];
// matB[m][j]=matB[i][j];
// matB[i][j]=t;
// }
// showMat("换位->:", matB, N, 2*N);
}
if (matB[m][m]==0)
{
continue;
}
// 增广矩阵形成上三角矩阵
for(i=m+1; i
{
matB[i][j] -= matB[m][j]*(matB[i][m]/matB[m][m]); //m=0时,将第一行的-matB[i][0]/matB[0][0]倍加到以下各行。这样以下每行第一个元素matB[i][0]就为0。
// showMat("上三->:", matB, N, 2*N);
}
// 对m行处理, 使得matB[m][m]=1
for(j=2*N-1; j>=m; j--)
{
matB[m][j] /= matB[m][m]; //对第m行作行变换,同除以matB[m][m],使matB[m][m]为1。
// showMat("归一->:", matB, N, 2*N);
}
}
// showMat("hah", matB, N, 2*N);
// 将左侧方阵的主对角线的右上侧置为0
m=N-1;
while(m>0)
{
for(int i=0;i
matB[i][j] -= matB[i][m] * matB[m][j]; // 其中Mat[i][m]作为系数
m--;
}
return;
}
/************************************************************************/
/*
功能: 从变化后的伴随矩阵中获取逆矩阵
输入: MatPlus:经高斯消元的伴随矩阵
MatInv:待存放逆矩阵元素的二维矩阵
n:二维矩阵的维数
输出: void
*/
/************************************************************************/
void getInv(double ** MatPlus, double ** MatInv, const int n)
{
for (int i=0; i
for (int j=0; j
MatInv[i][j] = MatPlus[i][n+j];
}
}
return;
}
/************************************************************************/
/*
功能: 释放矩阵内存
输入: Mat:二维矩阵的首元素地址
n:二维矩阵的维数
输出: void
*/
/************************************************************************/
void freeMem(double **Mat, const int n)
{
for (int i=0; i
free(*(Mat+i));
}
free(Mat);
return;
}
最后输入ctrl+x结束
好难啊