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时矩阵不可逆。解决方法:判断要逆的矩阵的行列式是不是为零,如果为零则退出。