用Java写一个求逆矩阵的程序 2.0
作者:互联网
用Java写一个求逆矩阵的程序 2.0
变更记录
对上次的源程序程序进行了少许改动,
修复了输入3阶以上的矩阵会出现数组下标超出的BUG
修复了矩阵的行列式的值没有除相应的分母的BUG
修复了对矩阵求余子式计算错乱的BUG
在源码上添加了一些必要的解释
简析
函数在计算逆矩阵时会先调用这个函数
public void InvsIntM(int[][] E,int step)
这也是求逆矩阵的核心函数,由这个函数来调用程序其他的模块,最终实现逆矩阵的运算。那么它具体怎么协调调用其他的函数的呢,我们来看一下这个函数的实现代码。
public void InvsIntM(int[][] E,int step)//计算逆矩阵进行函数调用的核心函数
{
int[][] A = new int[row][row];
for(int i = 0;i < row;i++)
for (int j = 0;j < row;j++)
A[i][j] = E[i][j];
CacuIntValue(A,row,1);
DeteValue.setFenzi(Value.getFenzi()/Value.getGcd());//将行列式的值设置为最简状态
DeteValue.setFenmu(Value.getFenmu()/Value.getGcd());
if(step == 1) {System.out.print("|A| = " );DeteValue.show();System.out.println("");}
if(DeteValue.getFenzi() == 0)
System.out.println("哎呦,|A| = 0 这是个奇异矩阵,不可逆!!!!");
else {
CompMatr(E,step);//调用求伴随矩阵的函数
for(int i = 0;i < row;i++)
for (int j = 0;j < row;j++)
CM[i][j] = new Fraction(CM[i][j].getFenzi()*DeteValue.getFenmu(),CM[i][j].getFenmu()*DeteValue.getFenzi());
if(step == 1)
{
System.out.println("A-1 = A* / |A| =");
}
CMShow();}
}
首先上去一个For循环目的是为了将所输入的矩阵进行备份,全部的都复制到数组A中,然后用这个数组A来作为调用计算本矩阵对应的行列式的值的参数之一, CacuIntValue(A,row,1);第二个数表示矩阵是几阶的,并且将其作为循环的限界条件。
计算完之后数据被分数类的对象Value 保存。并通过Value将矩阵对应的行列式的值的数据传给DeteValue,从此DeteValue保持不变,它就是所输入的矩阵对应的行列式的值。并且这个值如果是分数他一定是最简分数。
DeteValue.setFenzi(Value.getFenzi()/Value.getGcd());
DeteValue.setFenmu(Value.getFenmu()/Value.getGcd());
之后是一个IF语句来决定是否输出行列式的值
if(step == 1 )
{System.out.print("|A| = " );
DeteValue.show();
System.out.println("");
}
再往后再判断一下所输入的矩阵是否为奇异矩阵,即行列式为0 的矩阵
if( DeteValue.getFenzi() == 0 )
System.out.println(“哎呦,|A| = 0 这是个奇异矩阵,不可逆!!!!”);
else
否则才进行下面的计算:
调用求伴随矩阵的函数求出伴随矩阵的每一个元素然后存到一个数组中
对伴随矩阵中的每一个元素的值都除以DeteValue并把它赋值给 Fraction类的二维数组 CM中的相应位置的元素
CompMatr(E,step);//调用求伴随矩阵的函数
for(int i = 0;i < row;i++)
for (int j = 0;j < row;j++)
CM[i][j] = new Fraction(CM[i][j].getFenzi()*DeteValue.getFenmu(),CM[i][j].getFenmu()*DeteValue.getFenzi());
最后再判断是否要输出以下内容
if(step == 1)
{
System.out.println(“A-1 = A* / |A| =”);
}
最后调用输出最终结果的函数输出逆矩阵
CMShow();}
改进后的全部代码:
Main 函数:
package com.liable;
import java.util.Scanner;
public class Main extends Matrix{
public static void main(String[] args) {
int row,column;// 矩阵的行列数2
Scanner sc = new Scanner(System.in);
row = sc.nextInt();
column = row;
int[][] m = new int[row][column];
for(int i = 0;i < row;i++)
{
for(int j = 0 ; j < column; j++)
m[i][j] = sc.nextInt();
}
Matrix E = new Matrix(row);
E.setIntMatrix(m);
E.printInt(m,row);
System.out.println(" ");
E.InvsIntM(m,1);
sc.close();
}
}
Matrix 类 :
package com.liable;
public class Matrix extends Fraction{
private int row = 0,column = 0;//矩阵的行和列
//private int M[][];//整形的矩阵
private int Ma[][];//备份储存整形的矩阵的原始数据
private Fraction Value = new Fraction(1,1);//行列式的值,初始化为1
private Fraction DeteValue = new Fraction(1,1);//矩阵行列式的值,一旦求出不再改变
private Fraction matr[][];//分数型矩阵
private Fraction CM[][];//伴随矩阵
private int IMstep = 1;//决定是否生成步骤的,如果是那就是1默认不生成求解步骤
private int CMstep = 0;//伴随矩阵中余子式的步骤是否生成
Matrix(){}
Matrix(int row)
{
if(row == 0)
System.out.println("哎呦,行和列等于零咋算啊");
else if(row < 0)
System.out.println("哎呦,行列数小于0咋算啊");
else{
this.row = row;
column = row;}
}
Matrix(int row,int column)
{
if(row == 0 || column == 0)
System.out.println("哎呦,行和列等于零咋算啊");
else if(row < 0 || column < 0)
System.out.println("哎呦,行列数小于0咋算啊");
else{
this.row = row;
this.column = column;}
}
public void setIntMatrix(int[][] a)//初始化整形矩阵
{
if(row == 0 || column == 0)
System.out.println("哎呦,还没初始化行和列呢");
else{
// M = new int[row][column];
Ma = new int[row][column];
for(int i = 0; i < row;i++)
{
for(int j = 0; j < column;j++) {
// M[i][j] = a[i][j];
Ma[i][j] = a[i][j];
}
}}
//Value = CacuIntValue();//调用计算行列式的函数完成初始化
}
public void setFraMatrix(int a[][],int b[][])//初始化分数矩阵的成员
{
matr = new Fraction[row][column];
for(int i = 0; i < row;i++)
{
for(int j = 0; j < column;j++)
{
matr[i][j] = new Fraction(a[i][j],b[i][j]);
}
}
}
private void SwapMatr(int a, int b,int[][] M)//输入两个行数来交换二维数组的两行
{
for(int i = 0 ; i < column ;i++)
{
int temp = M[a][i];
M[a][i] = M[b][i];
M[b][i] = temp;
}
}
private void CaValCoeff(int i,int[][] Coeff,int[][] M,int R)//求出每一行与对角线元素对应行做差时的系数,并存在数组中
{ //如果要处理的是第一列,那么i=0
int k = 0; //并且这个2行10列的数组第一行存储对角元素下的行的系数
for(int j = i+1;j < R; j++)//第二行存储对角线元素所对应的行的系数
{
if(M[i][i] == M[j][i])
{
Coeff[0][k] = 1;
Coeff[1][k] = 1;
}
else if(M[i][i] < M[j][i] )
{
if(M[j][i] == 0) {
Coeff[0][k] = 1;
Coeff[1][k] = 0;
}
else if(M[j][i] % M[i][i] == 0){
Coeff[0][k]=1;
Coeff[1][k]=M[j][i]/M[i][i];
}else{
Coeff[0][k]=M[i][i];
Coeff[1][k]=M[j][i];
if(Coeff[0][k] < 0 && Coeff[1][k] < 0)
{
Coeff[0][k] *= -1;
Coeff[1][k] *= -1;
}
}
}
else if(M[i][i] > M[j][i])
{
if(M[j][i] == 0) {
Coeff[0][k] = 1;
Coeff[1][k] = 0;
}
else if( M[i][i] % M[j][i] == 0){
Coeff[0][k]=M[i][i]/M[j][i];
Coeff[1][k]=1;
}else{
Coeff[0][k]=M[i][i];
Coeff[1][k]=M[j][i];
if(Coeff[0][k] < 0 && Coeff[1][k] < 0)
{
Coeff[0][k] *= -1;
Coeff[1][k] *= -1;
}
}
}else;
k++;
}
}
private void MoveM(int i,int a,int b,int l,int[][] M,int R)//对已经确定系数的高阶行列式进行变换
{
for(int j = 0;j < R;j++)
{
M[i][j] = a*M[i][j]-b*M[l][j] ;
}
Value.setFenmu(Value.getFenmu()*a);
}
private void printCaIntVStep( int[][] Coeff,int j,int k,int i,int[][] M,int R)//负责输出计算矩阵对应行列式的值的过程
{
if(Coeff[0][k] == 0 && Coeff[1][k] == 0) {
System.out.print(" " + "r" + (i + 1) + "<->" + "r" + (j + 1));
System.out.print(" 系数:");
Value.show();
System.out.println(" ");
printInt(M,R);
System.out.println(" ");
}
else{ if(Coeff[0][k] == 1)
System.out.print(" ");
else
System.out.print(Coeff[0][k]);
System.out.print("r"+(j+1)+" - ");
if(Coeff[1][k] == 1)
System.out.print(" ");
else
System.out.print(Coeff[1][k]);
System.out.print("r"+(i+1));
System.out.print(" 系数:");
Value.show();
System.out.println(" ");
printInt(M,R);
System.out.println(" ");}
}
public Fraction CacuIntValue(int[][] M,int R ,int step)//求出所给方阵对应的行列式的值
{
if(R == 0)//先判断是几阶的,之后再选择用何种办法求
return Value = new Fraction(0,1);
else if(R == 1 )
return Value = new Fraction(M[0][0],1);
else if(R == 2)//二阶的直接求
{
int a = M[0][0]*M[1][1] - M[0][1]*M[1][0];
return Value = new Fraction(a,1);
}
else//对于3阶向上的用
{
for(int i = 0;i < R-1;i++)
{//把每一列的元素除了从上往下数对角线元素下面的都设置为零。
int a = 1, b = 1;
int[][] Coeff = new int[2][10];
int[][] Enmpty = new int [2][1];
Enmpty[0][0] = 0;
Enmpty[1][0] = 0;
if (M[i][i] == 0) //如果有对角线上的元素等于零
{
for(int k = (i+1); k < R; k++)
{//往下找看看有没有不等于零的元素,如果有就跟他交换元素
if (M[k][i] != 0)
{
SwapMatr(i, k,M);
Value.setFenzi(-1);
if(step == 1)
printCaIntVStep(Enmpty,k,0,i,M,R);
} else ;
}
continue;//走完for循环都没找到不为零的,那太好了
// 这一列(i列)从M [i][i]开始(包括M[i][i])往下都是0,还变换啥啊
} else
{
CaValCoeff(i,Coeff,M,R);//计算出每次做差的系数放到数组存起来
int k = 0;
for(int j = i+1;j < R;j++)
{
if(Coeff[0][k] == 1 && Coeff[1][k] == 0);
else
MoveM(j,Coeff[0][k],Coeff[1][k],i,M,R) ;//对矩阵进行相应的变换
if(step == 1)//是否输出步骤
printCaIntVStep(Coeff,j,k,i,M,R);//输出步骤
k++;
}
}
}
for(int i = 0; i < R;i++)
Value.setFenzi(Value.getFenzi()*M[i][i]);
Value.Setgcd();
return DeteValue;
}}
private void InitCofa(int[][] a,int[][] b, int i,int j)
{
int p = 0,q = 0;
for(int k = 0;k < row;k++)
{
if(k == i) continue;
else
for (int l = 0;l < row;l++)
{
if(l == j) continue;
else
{
a[p][q] = b[k][l];
q++;
if(q == row-1)
{
q = 0;
p++;
}
}
}
}
}
private void transCM()//对矩阵进行转置的函数,即进行行列互换
{
for(int i = 0;i < row;i++)
for (int j = i+1;j <row;j++)
{
if ((i + j + 2) % 2 != 0)
{
CM[i][j].setFenzi(-1*CM[i][j].getFenzi());
CM[j][i].setFenzi(-1*CM[j][i].getFenzi());
}
Fraction temp = new Fraction(CM[i][j].getFenzi(),CM[i][j].getFenmu());
CM[i][j] = new Fraction(CM[j][i].getFenzi(),CM[j][i].getFenmu());
CM[j][i] = new Fraction(temp.getFenzi(),temp.getFenmu());
}
}
private void printCompStep()//输出求余子式的计算过程的函数
{
System.out.println("余子式:");
for(int i = 0;i < row;i++) {
for (int j = 0; j < row; j++)
{
System.out.print("M"+(i+1)+(j+1)+" = ");
CM[i][j].show();
System.out.print(" ");
}
;
System.out.println(" ");
}
}
private void printCpMaStep()//输出伴随矩阵的函数
{
System.out.println("A* =");
for(int i = 0;i < row;i++) {
for (int j = 0; j < row; j++)
{
CM[i][j].show();
System.out.print(" ");
}
;
System.out.println(" ");
}
}
public void CompMatr(int[][] E,int step)//计算伴随矩阵的核心函数
{
int [][] Cofa = new int[row-1][row-1];//定义一个小一阶的数组来储存余子式cofactor
CM = new Fraction[row][row];
// if(row == 2)
for(int i = 0;i < row;i++)
{
for(int j = 0;j < row;j++)
{
InitCofa(Cofa,E,i,j);
Value = new Fraction(1,1);
CacuIntValue(Cofa, row-1,0);
CM[i][j] = new Fraction(Value.getFenzi(),Value.getFenmu());
Value = new Fraction(1,1);
}
}
if(step == 1)
printCompStep();
transCM();//调用转置矩阵的函数
if(step == 1)
printCpMaStep();
}
public void InvsIntM(int[][] E,int step)//计算逆矩阵进行函数调用的核心函数
{
int[][] A = new int[row][row];
for(int i = 0;i < row;i++)
for (int j = 0;j < row;j++)
A[i][j] = E[i][j];
CacuIntValue(A,row,1);
DeteValue.setFenzi(Value.getFenzi()/Value.getGcd());//将行列式的值设置为最简状态
DeteValue.setFenmu(Value.getFenmu()/Value.getGcd());
if(step == 1) {System.out.print("|A| = " );DeteValue.show();System.out.println("");}
if(DeteValue.getFenzi() == 0)
System.out.println("哎呦,|A| = 0 这是个奇异矩阵,不可逆!!!!");
else {
CompMatr(E,step);//调用求伴随矩阵的函数
for(int i = 0;i < row;i++)
for (int j = 0;j < row;j++)
CM[i][j] = new Fraction(CM[i][j].getFenzi()*DeteValue.getFenmu(),CM[i][j].getFenmu()*DeteValue.getFenzi());
if(step == 1)
{
System.out.println("A-1 = A* / |A| =");
}
CMShow();}
}
public void printInt(int[][] M,int R)//输出整型矩阵成员
{
for(int i = 0;i < R;i++) {
for (int j = 0; j < R; j++)
{if(M[i][j] >= 0)
System.out.print(" ");
System.out.print(String.format("%-3d",M[i][j]) + " " );
if(M[i][j] < 0)
System.out.print(" ");
}System.out.println();
}
}
public void printFra()//输出分数类的矩阵成员
{
for(int i = 0;i < row;i++) {
for (int j = 0; j < column; j++) {
matr[i][j].show();
System.out.print(" ");
}
System.out.println();
}
}
private void CMShow()//输出最终的逆矩阵 数据类型 分数类对象
{
for(int i = 0;i < row;i++) {
for (int j = 0; j < column; j++) {
CM[i][j].show();
System.out.print(" ");
}
System.out.println();
System.out.println();
}
}
public int GetIntMatr(int i,int j)
{
return Ma[i][j];
}
public void showOringIntM()//负责输出原始的矩阵
{
for(int i = 0;i < row;i++) {
for (int j = 0; j < column; j++)
{if(Ma[i][j] >= 0)
System.out.print(" ");
System.out.print(String.format("%-3d",Ma[i][j]) + " " );
if(Ma[i][j] < 0)
System.out.print(" ");
}System.out.println();
}
}
public Fraction GetFraMatr(int i,int j)
{
return matr[i][j];
}
void getValue() {
Value.show();
}
}
Fraction 类 分数类 :
package com.liable;
public class Fraction {
private int fenzi=0 , fenmu=1;
private int gcd = 0;///分子分母的最大公约数
private int abs(int x)
{
if(x < 0)
return -x;
return x;
}
private int f_gcd(int a, int b)///辗转相除法求两个正整数的最大公约数 例如:a=14 b = 21
{
if( a * b == 0)
return 1;
int g;
if(a < b)
{
int t = a;
a = b;
b = t;
}///a = 21 b = 14
g = b;///g = 14
while(a % b != 0)
{
g = a % b;///g = 7
a = b;///a = 14
b = g;///b = 7
}
return g;
}
Fraction(){}
Fraction(int fenzi)
{
this.fenzi = fenzi;
fenmu = 1;
gcd = 1;
}
Fraction(int fenzi, int fenmu )//:fenzi(fenzi), fenmu(fenmu)
{
this.fenzi = fenzi;
this.fenmu = fenmu;
gcd = f_gcd(abs(fenzi), abs(fenmu));
}
public void show()
{
if(fenmu == 0)
{
System.out.println("Error!!");
return;
}
if(fenzi == 0)
{
System.out.print("0");
return;
}
if(fenzi * fenmu < 0)
System.out.print("-");
else System.out.print(" ");//为了保证输出能做到行列对齐。如果前面没有负号输出一个空格来占一位
System.out.print(String.format("%-2d",abs(fenzi)/gcd));//分子最低占两位
if(abs(fenmu)/gcd != 1)
System.out.print("/"+ String.format("%-3d",abs(fenmu)/gcd));//分母最低占三位
else System.out.print(" ");
}
public void setFenzi(int fenzi) {
this.fenzi = fenzi;
}
public void setFenmu(int fenmu) {
this.fenmu = fenmu;
}
public void Setgcd()
{
gcd = f_gcd(abs(fenzi), abs(fenmu));
}//访问权限为公开的设置最大公约数的函数
public int getGcd(){ gcd = f_gcd(abs(fenzi), abs(fenmu)); return gcd; }
public int getFenmu() {
return fenmu;
}
public int getFenzi() {
return fenzi;
}
}
标签:求逆,Java,int,矩阵,System,++,2.0,out,row 来源: https://blog.csdn.net/Liablbility/article/details/113061686