• 列主元消去法&全主元消去法——Java实现


    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]));
    		}
    	}
    
    }
    
  • 相关阅读:
    第二阶段冲刺总结01
    第十四周学习进度
    第十三周进度
    意见改进
    BZOJ 2109 航空管制(拓扑排序+贪心)
    BZOJ 2131 圈地计划(最小割+黑白染色)
    BZOJ 2118 墨墨的等式(最短路)
    BZOJ 2157 旅行(树链剖分码农题)
    BZOJ 2141 排队(树状数组套主席树)
    BZOJ 2186 沙拉公主的困惑(预处理逆元+欧拉函数)
  • 原文地址:https://www.cnblogs.com/wowpH/p/11060855.html
Copyright © 2020-2023  润新知