首页 > 编程语言 > 如何基于java实现Gauss消元法过程解析
2020
10-13

如何基于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实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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][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 i = 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 + "和"+ 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型变量数值的函数,还真是有点不方便,必须采用一个数组对象来作为辅助,具体实现如下:

1
2
3
4
5
6
7
//交换两个整数
  private static void swap(int[] source, int i, int j) {
 
    int temp = source[i];
    source[i] = source[j];
    source[j] = temp;
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。

编程技巧