天天看点

C++ 矩阵求a*b-1及行列式、伴随矩阵和逆矩阵思想及源代码

C++求a*b逆和矩阵行列式伴随矩阵及逆矩阵

这是通过行列式和伴随矩阵求逆矩阵的方法,分别将求行列式、伴随矩阵的功能提取了出来, 逆矩阵 等于伴随矩阵/行列式。如果你想学习如何对矩阵求逆, 可以仔细阅读这篇文章,代码很好了解,很基础。

总程序在后面。

1.行列式

求行列式办法很多,本文采用对角线法则。即

C++ 矩阵求a*b-1及行列式、伴随矩阵和逆矩阵思想及源代码

等于(主对角线乘积与各“推移”主对角线乘积之和)减去(次对角线乘积与各“推移”对角线之和)。

举个例子

C++ 矩阵求a*b-1及行列式、伴随矩阵和逆矩阵思想及源代码

等于a1·b2·c3+b1·c2·a3+c1·a2·b3-a3·b2·c1-b3·c2·a1-c3·a2·b1。

可以分为加的部分减去减的部分。

对应代码为:

int detadd(int i,int j,int n,int temp[][100]){
	if(i<n){
		return temp[(i+n)%n][(j+n)%n]*detadd(++i,++j,n,temp);
	}else return 1;
}//二阶行列式对角线法则的加的部分 
int detnoadd(int i,int j,int n,int temp[][100]){
	if(i<n){
		return temp[(i+n)%n][(j+n)%n]*detnoadd(++i,--j,n,temp);
	}else return 1;
}//减的部分 
int det(int temp[][100],int n){
	int sum=0;
	int i=0,j=0;
	if(n==1){
		sum=temp[0][0];
	}else if(n==2){
		sum=temp[0][0]*temp[1][1]-temp[0][1]*temp[1][0];
	}else{
		for(j=0;j<n;j++){
			sum+=detadd(i,j,n,temp);
		}
		for(j=n-1;j>=0;j--){
			sum-=detnoadd(i,j,n,temp);
		}
	}
	return sum;
} 
           

n为矩阵维度,函数为传入矩阵返回行列式值。

2.伴随矩阵

设A=(aij)n×n是n阶方阵,由行列式|A|中的每个元素aij的代数余子式Aij所构成的矩阵A称为矩阵A的伴随矩阵。

注:伴随矩阵A在位置(i,j)上的元素是矩阵A在位置(j,i)上的代数余子式。

具体参考链接: link.

先求出代数余子式,然后分别放入伴随矩阵中做元素,求余子式需要除去本行和本列的数据,所以利用监视变量flag1和flag2,如果跳过了行列,那对应的余子式的行列下标相比于原来就要少1。

对应代码为:

void ac(int temp[][100],int temp1[][100],int i,int j,int n){
	bool flag1=false,flag2=false;
	int x,y,p,q;//x,y为代数余子式的坐标数,p,q为遍历数组的下标
	for(p=0;p<n;p++){//在矩阵中循环并监视行列,如果相等就跳过 
		if(p==i){
			p++;
			flag1=true;
		}
		flag2=false;
		for(q=0;q<n;q++){
			if(q==j){
				q++;
				flag2=true;
			} 
			x= flag1==true?p-1:p; //如果跳过了行列, 
			y= flag2==true?q-1:q;
			temp1[x][y]=temp[p][q];
		}
	}
}
void zz(int temp[][100],int n){//转置 
	for(int i=0;i<n;i++){
		for(int j=0;j<i;j++){
			swap(temp[i][j],temp[j][i]); 
		}
	}
}
void am(int temp[][100],int n){//1.求余子式2.求代数余子式3.伴随矩阵4.转置 
	int temp1[100][100];//临时余子式 algebraic complement
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){//求temp的伴随矩阵 
			ac(temp,temp1,i,j,n);//代数余子式 
//			printf("余子式%d%d\n",i,j);
//			print(temp1,n-1);//测试输出余子式 
			amj[i][j]=det(temp1,n-1)*pow(-1,i+j); //伴随矩阵对应的元素 
		}
	}
	zz(amj,n);//转置 
}
           

n为矩阵维度,函数为传入矩阵返回行列式值。

3.逆矩阵

本问矩阵求逆用到了行列式和伴随矩阵,如果要引用求逆,则需要应用伴随矩阵和行列式。

A逆: A⁻¹=A*/|A|

代码为:

/*矩阵求逆返回到amj矩阵*/ 
int iom(int temp1[][100],int n){//inverse of matrix
	if(det(temp1,n)!=0){
		am(temp1,n);//伴随矩阵返回到amj
		mathmult(amj,1.0/det(temp1,n),n);
	}else {//行列式等于零矩阵不可逆
		cout<<"矩阵不可逆"; 
		return -1;
	} 
}
           

将函数集成到交互式界面

代码:

#include<stdio.h>
#include<iostream>
#include<math.h> 
using namespace std; 
/*为矩阵分配空间*/ 
int a[100][100];//a矩阵 
int b[100][100];//b矩阵 
int amj[100][100];//伴随矩阵和逆矩阵和其他
int multj[100][100];//矩阵相乘 
/*交换*/
void swap(int *a,int *b){
	int c;
	c=*a;
	*a=*b;
	*b=c;
} 
/*建立矩阵(输入)*/
void init(int temp[][100],int n){
	cout<<"请输入"<<n<<"维矩阵 :"<<endl;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cin>>temp[i][j];	
		}
	}
} 
/*打印矩阵*/
void print(int temp[][100] ,int n) {//打印一个n维的矩阵
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cout<<temp[i][j]<<"  ";	
		}
		cout<<endl;
	}
	cout<<"----------------"<<endl;
}
/*矩阵求行列式(对角线法则)*/ 
int detadd(int i,int j,int n,int temp[][100]){
	if(i<n){
		return temp[(i+n)%n][(j+n)%n]*detadd(++i,++j,n,temp);
	}else return 1;
}//二阶行列式对角线法则的加的部分 
int detnoadd(int i,int j,int n,int temp[][100]){
	if(i<n){
		return temp[(i+n)%n][(j+n)%n]*detnoadd(++i,--j,n,temp);
	}else return 1;
}//减的部分 
int det(int temp[][100],int n){
	int sum=0;
	int i=0,j=0;
	if(n==1){
		sum=temp[0][0];
	}else if(n==2){
		sum=temp[0][0]*temp[1][1]-temp[0][1]*temp[1][0];
	}else{
		for(j=0;j<n;j++){
			sum+=detadd(i,j,n,temp);
		}
		for(j=n-1;j>=0;j--){
			sum-=detnoadd(i,j,n,temp);
		}
	}
	return sum;
} 
/*矩阵求伴随矩阵adjoint matrix输入到amj矩阵*/
void ac(int temp[][100],int temp1[][100],int i,int j,int n){
	bool flag1=false,flag2=false;
	int x,y,p,q;//x,y为代数余子式的坐标数,pq为遍历数组的下标
	for(p=0;p<n;p++){//在矩阵中循环并监视行列,如果相等就跳过 
		if(p==i){
			p++;
			flag1=true;
		}
		flag2=false;
		for(q=0;q<n;q++){
			if(q==j){
				q++;
				flag2=true;
			} 
			x= flag1==true?p-1:p; //如果跳过了行列, 
			y= flag2==true?q-1:q;
			temp1[x][y]=temp[p][q];
		}
	}
}
void zz(int temp[][100],int n){//转置 
	for(int i=0;i<n;i++){
		for(int j=0;j<i;j++){
			swap(temp[i][j],temp[j][i]); 
		}
	}
}
void am(int temp[][100],int n){//1.求余子式2.求代数余子式3.伴随矩阵4.转置 
	int temp1[100][100];//临时余子式 algebraic complement
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){//求temp的伴随矩阵 
			ac(temp,temp1,i,j,n);//代数余子式 
//			printf("余子式%d%d\n",i,j);
//			print(temp1,n-1);//测试输出余子式 
			amj[i][j]=det(temp1,n-1)*pow(-1,i+j); //伴随矩阵对应的元素 
		}
	}
	zz(amj,n);//转置 
}
/*矩阵相加*/
void mathadd(int temp[][100],int temp1[][100],int temp2[][100],int n){//返回到第一个矩阵 
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			temp[i][j]=temp1[i][j]+temp2[i][j];
		}
	}
} 
/*矩阵相减*/
void mathnoadd(int temp[][100],int temp1[][100],int temp2[][100],int n){//返回到第一个矩阵 
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			temp[i][j]=temp1[i][j]-temp2[i][j];
		}
	}
}
/*数乘矩阵*/
void mathmult(int temp[][100],double math,int n){
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			amj[i][j]*=math;
		}
	}
} 
/*矩阵相乘(两维度一样的矩阵相乘返回到multj矩阵)*/
void mult(int temp1[][100],int temp2[][100],int n){
	int i,j,z;
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			multj[i][j]=0;	
		}
	}
	for(i=0;i<n;i++){
		for(j=0;j<n;j++){
			for(z=0;z<n;z++){
				multj[i][j]+=temp1[i][z]*temp2[z][j];
			}	
		}
	}
}
/*矩阵求逆返回到amj矩阵*/ 
int iom(int temp1[][100],int n){//inverse of matrix
	if(det(temp1,n)!=0){
		am(temp1,n);//伴随矩阵返回到amj
		mathmult(amj,1.0/det(temp1,n),n);
	}else {//行列式等于零矩阵不可逆
		cout<<"矩阵不可逆"; 
		return -1;
	} 
}
int main(){
	int e=1,no,n;
	while(e==1){
		cout<<"选择操作:\n1.行列式\n2.伴随矩阵\n3.数乘矩阵\n4.矩阵相加\n5.矩阵相减\n6.矩阵相乘\n7.矩阵求逆\n8.求a*b-1\n9.退出\n---------------\n输入序号:";
		cin>>no;
		switch(no){
			
			case 1:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				cout<<"行列式为:"<<det(a,n);
				break;
			case 2:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				am(a,n);
				cout<<"伴随矩阵为:\n"; 
				print(amj,n);
				break;
			case 3:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				double x;
				cout<<"输入数"; 
				cin>>x;
				mathmult(a,x,n);
				cout<<"数乘矩阵为:\n"; 
				print(a,n);
				break;
			case 4:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				init(b,n);
				mathadd(amj,a,b,n);
				cout<<"矩两矩阵相加结果为:\n"; 
				print(amj,n);
				break;
			case 5:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				init(b,n);
				mathnoadd(amj,a,b,n);
				cout<<"两矩阵相减结果为:\n"; 
				print(amj,n);
				break;
			case 6:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				init(b,n);
				mult(a,b,n);
				cout<<"两矩阵相乘结果为:\n"; 
				print(multj,n);
				break;
			case 7:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				iom(a,n); 
				cout<<"矩阵求逆结果为:\n"; 
				print(amj,n);
				break;
			case 8:
				cout<<"输入矩阵维度:"; 
				cin>>n;
				init(a,n);
				init(b,n);
				iom(b,n);//b逆返回到amj矩阵 
				cout<<"-------------------\n";
				mult(a,amj,n);//a*b逆返回到multj矩阵 
				print(multj,n);
				break;
			case 9:
				cout<<"退出测试\n";
				goto exitwhile;
			default:
				cout<<"输入错误,重新输入!\n";
		} 
		getchar(); 
	    printf("\n\n是否继续?( 1 / 0 )\n");//提示是否退出
	    scanf("%d", &e);
	    system("cls");//清空屏幕
	} 
	exitwhile:
	
	return 0;
}
           

程序流程图为:

C++ 矩阵求a*b-1及行列式、伴随矩阵和逆矩阵思想及源代码

本程序函数基本含义:

程序有基本的对行列式的输入(init)输出(print)操作;

计算矩阵的行列式([det(矩阵,维度)]函数,返回行列式的值);

计算矩阵的伴随矩阵([am(矩阵,维度)],结果返回到amj数组);

矩阵相加([mathadd(矩阵1,矩阵2,矩阵3,维度));

矩阵相减([mathnoadd(矩阵1,矩阵2,矩阵3,维度)]);

矩阵相乘([mult(矩阵1,矩阵2,维度)],结果返回到multj矩阵);

数乘矩阵([mathmult(矩阵,数,维度)],结果返回到amj数组)的函数;

矩阵求逆([iom(矩阵,维度)])的函数结果返回到amj数组。

以下是本人在编写程序时遇到的问题及解决方法:

1.矩阵相乘时由于每次会相加乘积,如果程序多次运行矩阵相乘就会出现数据错误。解决方法:每次进行矩阵相乘的时候把矩阵清空。

2.矩阵求行列式按循环来写无法确定行列。解决方法:运用递归返回一条斜线的乘积。

3.矩阵求行列式时一维矩阵和二维矩阵无法求解。解决方法:监视行列如果为1或者2时单独处理。

4.矩阵求伴随矩阵时,需要求代数余子式。解决办法:通过建立监视变量来判断是否跳过行或列,如果跳过就把代数余子式的下标减一以保证代数余子式的数组连续。

5.矩阵如果行列式为0时矩阵不可逆。解决方法:判断要逆的矩阵的行列式是不是为零,如果为零则退出。