Gauss.java
package Gauss;
/**
* @description TODO 父類,包含高斯列主元消去法和全主元消去法的共有屬性和方法
* @author PengHao
* @date 2018年12月1日 上午9:44:40
*/
public class Gauss {
protected double[][] augmentedMatrix; // 增廣矩陣
protected int n = 0; // n階方陣
protected double[] root; // 方程組的根
protected int solution = 1; // 方程組解的個數,1唯一解,0無解,-1無窮解
/**
* @description TODO 構造方法,初始化各個屬性
* @date 2018年12月1日 下午12:04:44
* @param A 增廣矩陣
*/
public Gauss(double[][] A) {
this.n = A.length; // 方陣的階數
this.augmentedMatrix = new double[n][n + 1]; // 申請內存
for (int i = 0; i < this.n; i++) {
System.arraycopy(A[i], 0, this.augmentedMatrix[i], 0, this.n + 1); // 拷貝A的第i行到augmentedMatrix的第i行,每行n+1個數據
}
}
/**
* @description TODO 將增廣矩陣的兩行互換,注意不是整行
* @date 2018年12月1日 下午1:33:45
* @param rowSmall 要交換的較小的行下標
* @param rowBig 要交換的較大的行下標
*/
protected void rowSwap(int rowSmall, int rowBig) {
for(int j = rowSmall; j <= this.n; j++) { // 將這兩行的第rowSmall列至第n列交換
this.valueSwap(rowSmall, j, rowBig, j);
}
}
/**
* @description TODO 將增廣矩陣的值交換
* @date 2018年12月1日 下午1:31:05
* @param rowOne 第1個值的行下標
* @param colOne 第1個值的列下標
* @param rowTwo 第2個值的行下標
* @param colTwo 第2個值的列下標
*/
protected void valueSwap(int rowOne, int colOne, int rowTwo, int colTwo) {
double temp = this.augmentedMatrix[rowOne][colOne];
this.augmentedMatrix[rowOne][colOne] = this.augmentedMatrix[rowTwo][colTwo];
this.augmentedMatrix[rowTwo][colTwo] = temp;
}
/**
* @description TODO 消元過程
* @date 2018年12月1日 下午1:48:45
* @param k 消去第k行第k列以下的元素
*/
protected void elimination(int k) {
double temp; // 記錄第k列的第i行除以第k行的數,即倍數關系
for(int i = k + 1; i < this.n; i++) {
temp = this.augmentedMatrix[i][k] / this.augmentedMatrix[k][k];
for(int j = k + 1; j <= this.n; j++) {
this.augmentedMatrix[i][j] -= this.augmentedMatrix[k][j] * temp; // 第i行第j列等於它減去第k行第j列乘以除數temp
}
}
}
/**
* @description TODO 計算並設置方程組的解的狀態
* @date 2018年12月1日 下午2:24:46
*/
protected void setSolution() {
int rankOfC = this.n; // 系數矩陣的秩
int rankOfA = this.n; // 增廣矩陣的秩
boolean zero = false; // 系數矩陣的當前行是否全為0
for(int i = this.n - 1; i >= 0; i--) { // n行
zero = true; // 初始化全為0
for(int j = i; j < this.n; j++) { // 遍歷第i行的第i列至第n-1列
if(0 != this.augmentedMatrix[i][j]) { // [i][j]不等於0
zero = false; // 不全為0
break; // 退出遍歷
}
}
if(true == zero) { // 如果全為0
rankOfC--; // 系數矩陣的秩減1
if(0 == this.augmentedMatrix[i][n]) { // 如果常數矩陣的第i行為0
rankOfA--; //增廣矩陣的秩減1
}
} else { // 不全為0
break; // 退出求秩
}
}
if(rankOfC < rankOfA) { // 系數矩陣的秩小於增廣矩陣的秩
this.solution = 0; // 無解
} else if(rankOfC == rankOfA && rankOfC < this.n) { // 系數矩陣的秩等於增廣矩陣的秩
this.solution = -1; // 無窮解
}
}
}
ColumnPivot.java
package Gauss;
/**
* @description TODO 列主元消去法
* @author PengHao
* @date 2018年12月1日 下午12:15:15
*/
public class ColumnPivot extends Gauss {
/**
* @description TODO 列主元的構造方法,初始化父類
* @date 2018年12月1日 下午12:18:07
* @param A
*/
public ColumnPivot(double[][] A) {
super(A); // 顯式調用父類的構造方法
}
/**
* @description TODO 計算方程組的根並返回
* @date 2018年12月1日 下午12:38:48
* @return 方程組的根
*/
public double[] getRoot() {
for(int k = 0; k < this.n - 1; k++) { // n階循環n-1次
this.columnPivoting(k); // 在第k列選擇主元
this.elimination(k); // 消元過程
}
this.setSolution(); // 計算解的個數
if(1 == this.solution) { // 唯一解
this.backSubstitution(); // 回代求根
} else if(0 == this.solution) { // 無解
System.out.println("方程組無解!!!");
System.exit(0); // 退出程序
} else if(-1 == this.solution) {
System.out.println("方程組有無窮解!!!");
System.exit(0); // 退出程序
}
return this.root;
}
/**
* @description TODO 列選主元
* @date 2018年12月1日 下午1:51:49
* @param k 在第k列選主元
*/
private void columnPivoting(int k) {
int maxRow = k; // 記錄第k列最大的行下標
double max = Math.abs(this.augmentedMatrix[k][k]); // 記錄[k][k]至[n-1][k]中最大的數
double now; // 記錄當前的值,用於和max比較
for(int i = k + 1; i < this.n; i++) { // 第k行以下的都要比較
now = Math.abs(this.augmentedMatrix[i][k]); // 第k列第i行的絕對值
if(now > max) { // 第i行第k列的數比當前的最大值更大
max = now; // 更新最大值為當前值
maxRow = i; // 記錄最大值所在行
}
}
this.rowSwap(k, maxRow); // 行交換
}
/**
* @description TODO 回代求根
* @date 2018年12月1日 下午2:48:33
*/
private void backSubstitution() {
this.root = new double[this.n]; // 申請內存
for(int i = this.n - 1; i >= 0; i--) { // 回代n次
for(int j = this.n - 1; j > i; j--) {
this.augmentedMatrix[i][n] -= this.augmentedMatrix[i][j] * this.root[j];
}
this.root[i] = this.augmentedMatrix[i][n] / this.augmentedMatrix[i][i];
}
}
}
CompletePivot.java
package Gauss;
/**
* @description TODO 全主元消去法
* @author PengHao
* @date 2018年12月1日 下午3:00:31
*/
public class CompletePivot extends Gauss {
private int[] rootOrder; // 全主元會改變根的順序,用這個記錄變化
/**
* @description TODO 全主元的構造方法,初始化屬性
* @date 2018年12月1日 下午3:00:31
*/
public CompletePivot(double[][] A) {
super(A); // 顯式調用父類的構造方法
rootOrder = new int[this.n]; // 申請內存
for(int i = 0; i < this.n; i++) {
rootOrder[i] = i; // 初始化根的順序
}
}
/**
* @description TODO 計算方程組的根並返回
* @date 2018年12月1日 下午3:49:02
* @return 返回方程組的根
*/
public double[] getRoot() {
for(int k = 0; k < this.n - 1; k++) { // n階循環n-1次
this.completePivoting(k); // 在第k行第k列的右下方陣部分全選主元
this.elimination(k); // 消元過程
}
this.setSolution(); // 計算解的個數
if(1 == this.solution) { // 唯一解
this.backSubstitution(); // 回代求根
} else if(0 == this.solution) { // 無解
System.out.println("方程組無解!!!");
System.exit(0); // 退出程序
} else if(-1 == this.solution) {
System.out.println("方程組有無窮解!!!");
System.exit(0); // 退出程序
}
return this.root;
}
/**
* @description TODO 在第k行第k列的右下方陣部分全選主元
* @date 2018年12月1日 下午3:37:56
* @param k 全選主元部分的左上角的數的行下標和列下標
*/
private void completePivoting(int k) {
int maxRow = k, maxCol = k; //記錄最大數的行下標和列下標
double max = Math.abs(this.augmentedMatrix[k][k]); // 記錄最大值
double now; // 記錄當前值,用於和max比較
for(int i = k; i < this.n; i++) {
for(int j = k; j < this.n; j++) {
now = Math.abs(this.augmentedMatrix[i][j]); // 第i行第j列的絕對值
if(now > max) { // 當前值比最大值更大
max = now; // 更新最大值
maxRow = i; // 記錄最大值所在行
maxCol = j; // 記錄最大值所在列
}
}
}
this.rowSwap(k, maxRow); // 行交換
this.colSwap(k, maxCol); // 列交換
}
/**
* @description TODO 交換列
* @date 2018年12月1日 下午3:36:14
* @param colSmall 要交換的較小列下標
* @param colBig 要交換的較大列下標
*/
private void colSwap(int colSmall, int colBig) {
for(int i = 0; i < this.n; i++) { // 將這兩列的第0行至第n-1行交換
this.valueSwap(i, colSmall, i, colBig);
}
// 交換根的順序
int temp = rootOrder[colSmall];
rootOrder[colSmall] = rootOrder[colBig];
rootOrder[colBig] = temp;
}
/**
* @description TODO 回代求根
* @date 2018年12月1日 下午3:45:17
*/
private void backSubstitution() {
this.root = new double[this.n]; // 申請內存
for(int i = this.n - 1; i >= 0; i--) { // 回代n次
for(int j = this.n - 1; j > i; j--) {
this.augmentedMatrix[i][n] -= this.augmentedMatrix[i][j] * this.root[this.rootOrder[j]];
}
this.root[this.rootOrder[i]] = this.augmentedMatrix[i][n] / this.augmentedMatrix[i][i];
}
}
}
Test.java
package Test;
import Gauss.ColumnPivot;
import Gauss.CompletePivot;
/**
* @description TODO 測試類
* @author PengHao
* @date 2018年12月1日 上午9:56:31
*/
public class Test {
/**
* @description TODO 主方法,程序入口
* @date 2018年12月1日 上午9:56:31
* @param args
*/
public static void main(String[] args) {
int ORDERS = 4; // 階數
double[][] augmentedMatrix = {
{ 2, 10, 0, -3, 10 },
{ -3, -4, -12, 13, 5 },
{ 1, 2, 3, -4, -2 },
{ 4, 14, 9, -13, 7 }
}; // 根是1,2,3,4
// double[][] augmentedMatrix = {
// { 1, 2, 3, 10 },
// { 4, 3, 1, 19 },
// { 2, 5, 2, 18 }
// }; // 根是3,2,1
double[] root; // 保存方程組的根
ColumnPivot col = new ColumnPivot(augmentedMatrix);
root = col.getRoot(); // 獲取列主元消去法的方程組的根
printRoot(root, ORDERS, "列主元消去法");
CompletePivot com = new CompletePivot(augmentedMatrix);
root = com.getRoot();
printRoot(root, ORDERS, "全主元消去法");
}
/**
* @description TODO 輸出根
* @date 2018年12月1日 下午4:00:40
* @param root 根的數組
* @param n 數組的長度,即根的個數
* @param description 輸出文字描述
*/
static void printRoot(double[] root, int n, String description) {
System.out.println(description);
for(int i = 0; i < n; i++) {
System.out.println("X" + (i + 1) + "=" + String.format("% 6.2f", root[i]));
}
}
}