计算逆矩阵是矩阵计算中的一个较为重要的一个部分
1.逆矩阵的定义
设A是一个n阶矩阵,若存在另一个n阶矩阵B,使得: AB=BA=E ,则称方阵A可逆,并称方阵B是A的逆矩阵
2.矩阵可逆的充要条件
<1>A的标准形为单位矩阵E.
<2>A与单位矩阵E等价.
<3>行列式不等于0/r(A)=n
3.逆矩阵的计算
逆矩阵有很多计算方法,我选用的是 用初等变换求矩阵的逆
4.问题的分解
1.输入矩阵
2.实现三种初等变换
3.生成一个n阶的单位矩阵
4.循环调用三种初等变换将原矩阵化为标准形
5.用相同的步骤将n阶单位矩阵进行转化,结果就是矩阵的逆
5.代码实现
矩阵的输入
需要注意的是不能定义为int[][],在后续计算时,会有浮点数参与计算,int会造成问题
public static double[][] input(){
Scanner scanner = new Scanner(System.in);
System.out.println("n*n矩阵的n值");
int n = scanner.nextInt();
double[][] arr = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
arr[i][j] = scanner.nextDouble();
}
}
return arr;
}
生成一个n阶单位矩阵
后续计算中是需要对同阶的单位矩阵进行相应的运算,需要再生成一个单位矩阵 注意这个必须返回,不然会被JVM机释放
public static double[][] GetIdentityMatrix(int n){//得到n阶单位矩阵
double[][] Arr = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(i==j){
Arr[i][j] = 1;
}else {
Arr[i][j] = 0;
}
}
}
return Arr;
}
实现三种初等变换
三种初等变换
1.对调两行
2.非零常数乘某行
3.乘k加到另一行列
分别定义三个方法,进行变换即可,因为数组为引用传值,所以不必返回, 实现两行的对换,其实就是先把原数据用临时变量提取出来,对换即可,行和列需要一个字符去判断
public static void ExchangeTwo(double[][] Matrix, int a,int b,char RC){
double[] temp = new double[Matrix[a-1].length];
if(RC == 'r'){
for (int i = 0; i < Matrix[a-1].length; i++) {
temp[i] = Matrix[a-1][i];
Matrix[a-1][i] = Matrix[b-1][i];
Matrix[b -1][i] = temp[i];
}
}else {
for (int i = 0; i < Matrix.length; i++) {
temp[i] = Matrix[i][a-1];
Matrix[i][a-1] = Matrix[i][b-1];
Matrix[i][b-1] = temp[i];
}
}
}
非零常数乘某行呢,其实大差不差,遍历乘上即可
public static void MultiNum(double[][] Matrix,int a,double b,char RC){
if(RC == 'r'){
for (int i = 0; i < Matrix[a-1].length; i++) {
Matrix[a-1][i] = Matrix[a-1][i]*b;
}
}else {
for (int i = 0; i < Matrix.length; i++) {
Matrix[i][a-1] = Matrix[i][a-1]*b;
}
}
}
乘k加到另一行列,这个相对来说挺重要,后续核心基本就是在调用这个方法
public static void MutiNumRC(double[][] Matrix,double k,int a,int b,char RC){
if(RC == 'r'){
for (int i = 0; i < Matrix[a-1].length; i++) {
Matrix[a-1][i] = Matrix[a-1][i]+Matrix[b-1][i]*k;
}
}else {
for (int i = 0; i < Matrix.length; i++) {
Matrix[i][a-1] = Matrix[i][a-1]+Matrix[i][a-1]*k;
}
}
}
循环调用三种初等变换将原矩阵化为标准形
接着分解问题
1.生成对应的单位矩阵
double[][] IdentityMatrix = GetIdentityMatrix(Matrix.length);
2.调用第三种初等变换去将原矩阵先化为下三角,再化为初等矩阵
3.在变换原矩阵前,先变换生成的初等矩阵
for (int i = 1; i <= Matrix.length; i++) {
for (int j = i+1; j <= Matrix.length; j++) {
System.out.println("r"+j+(-(Matrix[j-1][i-1]/Matrix[i-1][i-1]))+"r"+i);
MutiNumRC(IdentityMatrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
MutiNumRC(Matrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
}
}//下三角
for (int i = Matrix.length; i >=1; i--) {
for (int j = i-1; j>=1; j--) {
MutiNumRC(IdentityMatrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
MutiNumRC(Matrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
}
}
4.最后要保证原矩阵变换为初等矩阵
写一个判断方法
public static boolean checkIdentity(double[][] Matrix){
boolean ans = true;
for (int i = 0; i < Matrix.length; i++) {
for (int j = 0; j < Matrix.length; j++) {
if (!((i == j && Matrix[i][j] == 1) || Matrix[i][j] == 0)){
ans = false;
break;
}
}
}
return ans;
}
对变换完的原始矩阵进行判断和更正
if(checkIdentity(Matrix)){
return IdentityMatrix;
}else {
for (int i = 1; i <= Matrix.length; i++) {
MultiNum(IdentityMatrix,i,1/Matrix[i-1][i-1],'r');
MultiNum(Matrix,i,1/Matrix[i-1][i-1],'r');
}
return IdentityMatrix;
}
最后是该方法的完整代码
public static double[][] Get(double[][] Matrix){
double[][] IdentityMatrix = GetIdentityMatrix(Matrix.length);
for (int i = 1; i <= Matrix.length; i++) {
for (int j = i+1; j <= Matrix.length; j++) {
System.out.println("r"+j+(-(Matrix[j-1][i-1]/Matrix[i-1][i-1]))+"r"+i);
MutiNumRC(IdentityMatrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
MutiNumRC(Matrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
}
}//下三角
for (int i = Matrix.length; i >=1; i--) {
for (int j = i-1; j>=1; j--) {
MutiNumRC(IdentityMatrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
MutiNumRC(Matrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
}
}
if(checkIdentity(Matrix)){
return IdentityMatrix;
}else {
for (int i = 1; i <= Matrix.length; i++) {
MultiNum(IdentityMatrix,i,1/Matrix[i-1][i-1],'r');
MultiNum(Matrix,i,1/Matrix[i-1][i-1],'r');
}
return IdentityMatrix;
}
}
最后需要补充的是
方法对于对角线上初始有0和不可逆的矩阵会出现问题
比如
这时需要去修改一下Get方法中的逻辑,在初始时先检测一下对角线是否有0,再写一个方法去换一下某几行即可
检查是否对角线是否有0
public static boolean checkMatrix(double[][] Matrix){
for (int i = 0; i < Matrix.length; i++) {
for (int j = 0; j < Matrix.length; j++) {
if(i==j&&Matrix[i][j]==0){
return true;
}
}
}
return false;
}
调整方法
public static void exchange(double[][] Matrix){
for (int i = 0; i < Matrix.length; i++) {
if(Matrix[i][i]==0){
for (int j = i; j < Matrix.length; j++) {
if(Matrix[j][i]!=0&&Matrix[j][j]!=0){
ExchangeTwo(Matrix,j,i,'c');
}
}
}
}
}
现在就只有初始矩阵不可逆的问题了。
而不可逆的判断其实可以在计算过程中稍着判断, 或者可以让它带着错误去计算,去看最后的的矩阵是否为正常矩阵, 这里选择后者。
for (int i = 0; i < Matrix.length; i++) {
for (int j = 0; j < Matrix.length; j++) {
if(!(Matrix[i][j]>=0||Matrix[i][j]<0)){
System.out.println("不可逆");
return null;
}
}
}
至此,所有步骤都已经完成。整体思路很简单,但是前提是手算逆矩阵都先会。这很重要。
最后会在以后补充的
最后结果为小数,这样子其实不太美观,这个会在以后去写一个将浮点数转化为分数的方法去解决,以后(考完试)
完整代码
下来是完整代码/
package project_self.InverseMatrix;
import java.util.Scanner;
public class Main {
/*
三种初等变换
1.对调两行
2.非零常数乘某行
3.乘k加到另一行列
*/
public static void ExchangeTwo(double[][] Matrix, int a,int b,char RC){
double[] temp = new double[Matrix[a-1].length];
if(RC == 'r'){
for (int i = 0; i < Matrix[a-1].length; i++) {
temp[i] = Matrix[a-1][i];
Matrix[a-1][i] = Matrix[b-1][i];
Matrix[b -1][i] = temp[i];
}
}else {
for (int i = 0; i < Matrix.length; i++) {
temp[i] = Matrix[i][a-1];
Matrix[i][a-1] = Matrix[i][b-1];
Matrix[i][b-1] = temp[i];
}
}
}
public static void MultiNum(double[][] Matrix,int a,double b,char RC){
if(RC == 'r'){
for (int i = 0; i < Matrix[a-1].length; i++) {
Matrix[a-1][i] = Matrix[a-1][i]*b;
}
}else {
for (int i = 0; i < Matrix.length; i++) {
Matrix[i][a-1] = Matrix[i][a-1]*b;
}
}
}
public static void MutiNumRC(double[][] Matrix,double k,int a,int b,char RC){
if(RC == 'r'){
for (int i = 0; i < Matrix[a-1].length; i++) {
Matrix[a-1][i] = Matrix[a-1][i]+Matrix[b-1][i]*k;
}
}else {
for (int i = 0; i < Matrix.length; i++) {
Matrix[i][a-1] = Matrix[i][a-1]+Matrix[i][a-1]*k;
}
}
}
public static double[][] Get(double[][] Matrix){
double[][] IdentityMatrix = GetIdentityMatrix(Matrix.length);
if(checkMatrix(Matrix)){
exchange(Matrix);
}
for (int i = 1; i <= Matrix.length; i++) {
for (int j = i+1; j <= Matrix.length; j++) {
System.out.println("r"+j+(-(Matrix[j-1][i-1]/Matrix[i-1][i-1]))+"r"+i);
MutiNumRC(IdentityMatrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
MutiNumRC(Matrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
}
}//下三角
for (int i = Matrix.length; i >=1; i--) {
for (int j = i-1; j>=1; j--) {
MutiNumRC(IdentityMatrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
MutiNumRC(Matrix,-(Matrix[j-1][i-1]/Matrix[i-1][i-1]),j,i,'r');
}
}
for (double[] matrix : Matrix) {
for (int j = 0; j < Matrix.length; j++) {
if (!(matrix[j] >= 0 || matrix[j] < 0)) {
System.out.println("不可逆");
return null;
}
}
}
if(checkIdentity(Matrix)){
return IdentityMatrix;
}else {
for (int i = 1; i <= Matrix.length; i++) {
MultiNum(IdentityMatrix,i,1/Matrix[i-1][i-1],'r');
MultiNum(Matrix,i,1/Matrix[i-1][i-1],'r');
}
return IdentityMatrix;
}
}
public static boolean checkIdentity(double[][] Matrix){
boolean ans = true;
for (int i = 0; i < Matrix.length; i++) {
for (int j = 0; j < Matrix.length; j++) {
if (!((i == j && Matrix[i][j] == 1) || Matrix[i][j] == 0)){
ans = false;
break;
}
}
}
return ans;
}
public static double[][] GetIdentityMatrix(int n){//得到n阶单位矩阵
double[][] Arr = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(i==j){
Arr[i][j] = 1;
}else {
Arr[i][j] = 0;
}
}
}
return Arr;
}
public static double[][] input(){
Scanner scanner = new Scanner(System.in);
System.out.println("n*n矩阵的n值");
int n = scanner.nextInt();
double[][] arr = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
arr[i][j] = scanner.nextDouble();
}
}
return arr;
}
public static void printArr(double[][] arr){
for (double[] ints : arr) {
for (int j = 0; j < arr.length; j++) {
System.out.printf("%.2f\t",ints[j]);
}
System.out.println();
}
}
public static boolean checkMatrix(double[][] Matrix){
for (int i = 0; i < Matrix.length; i++) {
for (int j = 0; j < Matrix.length; j++) {
if(i==j&&Matrix[i][j]==0){
return true;
}
}
}
return false;
}
public static void exchange(double[][] Matrix){
for (int i = 0; i < Matrix.length; i++) {
if(Matrix[i][i]==0){
for (int j = i; j < Matrix.length; j++) {
if(Matrix[j][i]!=0&&Matrix[j][j]!=0){
ExchangeTwo(Matrix,j,i,'c');
}
}
}
}
}
public static void main(String[] args) {
double[][] Matrix = input();
double[][] ans = Get(Matrix);
if(ans!=null){
printArr(ans);
}else {
System.out.println("结束了");
}
}
}
只怪本人没文化,一局卧槽走天下,真的c