计算逆矩阵是矩阵计算中的一个较为重要的一个部分
1.逆矩阵的定义
设A是一个n阶矩阵,若存在另一个n阶矩阵B,使得: AB=BA=E ,则称方阵A可逆,并称方阵B是A的逆矩阵
2.矩阵可逆的充要条件
- A的标准形为单位矩阵E.
- A与单位矩阵E等价.
- 行列式不等于0/r(A)=n
3.逆矩阵的计算
逆矩阵有很多计算方法,我选用的是 用初等变换求矩阵的逆
4.问题的分解
- 输入矩阵
- 实现三种初等变换
- 生成一个n阶的单位矩阵
- 循环调用三种初等变换将原矩阵化为标准形
- 用相同的步骤将n阶单位矩阵进行转化,结果就是矩阵的逆
5.代码实现
1.矩阵的输入
需要注意的是不能定义为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;
2.生成一个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;
}
3.实现三种初等变换
三种初等变换
1.对调两行
2.非零常数乘某行
3.乘k加到另一行列
分别定义三个方法,进行变换即可,因为数组为引用传值,所以不必返回, 实现两行的对换,其实就是先把原数据用临时变量提取出来,对换即可,行和列需要一个字符去判断
非零常数乘某行呢,其实大差不差,遍历乘上即可
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;
}
}
}
3.循环调用三种初等变换将原矩阵化为标准形
- 生成对应的单位矩阵
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');
}
}
最后要保证原矩阵变换为初等矩阵
判断如下
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("结束了");
}
}
}
最后,此篇文章转自于室友栋dong的博客,一起学习数学被"虐",转载此篇文章也得到了他的同意,故在此重申说明一下。
2 条评论
原作者来了,欢迎到我站点来视察
six