天天看點

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時矩陣不可逆。解決方法:判斷要逆的矩陣的行列式是不是為零,如果為零則退出。