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;
}
程式流程圖為:
本程式函數基本含義:
程式有基本的對行列式的輸入(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時矩陣不可逆。解決方法:判斷要逆的矩陣的行列式是不是為零,如果為零則退出。