如何基于java实现Gauss消元法过程解析

网友投稿 294 2022-11-18


如何基于java实现Gauss消元法过程解析

补充知识:

正定矩阵

奇异矩阵

严格对角占优

要理解Gauss消去法,首先来看一个例子:

从上例子可以看出,高斯消去法实际上就是我们初中学的阶二元一次方程组,只不过那里的未知数个数$n=2$

$n>2$时,Gauss消去法的思路实际上和解二元一次方程组是一样的,方法如下:

将n方程组中的n−1个方程通过消元,形成一个与原方程组等价的一个新方程组,新方程组中的n−1个方程仅包含n−1个未知数。

故问题就转化为了求解n−1元的方程组,这样我们可以继续消元,以次类推,直到最后一个方程组为一元一次方程组

从最后一个一元一次方程组求解出最后一个未知量,然后逐步回代入之前的方程组,从而得到所有的未知数。

我们可以看到Gauss实际上就分为两步:消去和回代

下面通过一般化得到Gauss消元法的求解过程

以上就是Gauss消去法的基本步骤,我们再回过头看看有没有什么问题?

我们在求比例$l_{ik}= \frac{a_{ik}^{\left (k-1 \right )}}{a_{kk}^{\left (k-1 \right )}}$时,如果分母很小,即:

$l_{ik}\rightarrow \infty$,那么

总结一下,能否使用Gauss消元法的情况

为了解决这个问题,我们可以使用列主元Gauss消元法。

参考了一些网上的代码,这里给出Gauss的java实现

package peterxiazhe;

import java.util.Scanner;

public class Gauss {

/**

* 列主元高斯消去法

*/

static double A[][];

static double b[];

static double x[];

static int n; //n表示未知数的个数

static int n_2; //记录换行的次数

public static void main(String[] args) {

System.out.println("--------------输入方程组未知数的个数---------------");

Scanner sc = new Scanner(System.in);

n = sc.nextInt();

A = new double[n][n];

b = new double[n];

x = new double[n];

System.out.println("--------------输入方程组的系数矩阵A:---------------");

for(int i = 0; i < n; i++) {

for(int j = 0; j < n; j++) {

A[i][j] = sc.nextDouble();

}

}

System.out.println("--------------输入方程组的常量向量b:---------------");

for(int i = 0; i < n; i++) {

b[i] = sc.nextDouble();

}

Elimination();

BackSubstitution();

PrintRoot();

}

//消元法

public static void Elimination() {

PrintA();

for(int k = 0; k < n; k++) {

WrapRow(k);

for(int i = k+1; i < n; i++) {

double l = A[i]ZsKcqbYS[k] / A[k][k];

A[i][k] = 0;

for(int j = k+1; j < n; j++) {

A[i][j] = A[i][j] - l * A[k][j];

}

b[i] = b[i] - l * b[k];

}

//System.out.println("第" + k + "次消元后:");

//PrintA();

}

}

//回代法

public static void BackSubstitution() {

x[n-1] = b[n-1] / A[n-1][n-1];

for(int i = n - 2; i >= 0; i--) {

x[i] = (b[i] - solve(i)) / A[i][i];

}

}

public static double solve(int i) {

double result = 0.0;

for(int j = i; j < n; j++)

result += A[i][j] * x[j];

return result;

}

//输出方程组的根

public static void PrintRoot() {

System.out.println("--------------方程组的根为---------------");

for(int i = 0; i < n; i++) {

System.out.println("x" + (i+1) + " = " + x[i]);

}

}

//交换Swap函数???

public static void Swap(double[] ar, int x, int y) {

Double tmp = ar[x];

ar[x] = ar[y];

ar[y] = tmp;

}

public static void PrintA() { //输出A的增广矩阵

//System.out.println("--------------增广矩阵---------------");

for(int ZsKcqbYSi = 0; i < n; i++) {

for(int j = 0; j < n; j++) {

System.out.print(A[i][j] + " ");

}

System.out.println(b[i]);

}

}

//交换矩阵的行

public static void WrapRow(int k) { //k表示第k+1轮消元

double maxElement = Math.abs(A[k][k]);

int WrapRowIndex = k; // 记住要交换的行

for(int i = k + 1; i < n; i++) {

if (Math.abs(A[i][k]) > maxElement) {

WrapRowIndex = i;

maxElement = A[i][k];

}

}

if (WrapRowIndex != k) { //交换求得最大主元

n_2 += 1;

System.out.println("k = " + k + "时," + "要交换的行为" + k http://+ "和"+ WrapRowIndex);

//先交换A

for(int j = k; j < n; j++) {

double[] arr = {A[k][j], A[WrapRowIndex][j]};

Swap(arr, 0, 1);

A[k][j] = arr[0]; A[WrapRowIndex][j] = arr[1];

// double tmp = A[k][j];

// A[k][j] = A[WrapRowIndex][j];

// A[WrapRowIndex][j] = tmp;

}

//再交换b

double[] arr = {b[k], b[WrapRowIndex]};

Swap(arr, 0, 1);

b[k] = arr[0]; b[WrapRowIndex] = arr[1];

// double tmp = b[k];

// b[k] = b[WrapRowIndex];

// b[WrapRowIndex] = tmp;

System.out.println("--------------交换后---------------");

PrintA();

}

}

}

注意:由于Java不支持对基本数据类型的引用传递,这里使用了一个小技巧

java中交换两个基本数据类型的变量函数swap(int[] source,int i,int j)

java中函数的参数传递机制是:基本数据类型采用值传递,对象采用传引用。因此,如果要写一个交换两个int型变量数值的函数,还真是有点不方便,必须采用一个数组对象来作为辅助,具体实现如下:

//交换两个整数

private static void swap(int[] source, int i, int j) {

int temp = source[i];

source[i] = source[j];

source[j] = temp;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot 创建容器的实现
下一篇:手动编译并运行Java项目实现过程解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~