c语言消去行或列步骤最少,列主元高斯消去法的实现,并且每一次的消去过程都要寻找全主元(C语言代码)...

一、程序分析

首先要求用户输入方程组的个数n,然后再输入相应的方程组的系数,系数用一个二维数组保存,这个数组的大小为n * (n+1),共n行,每行有n+1个元素,这是因为在输入系数矩阵的同时,也把常数列b输进去,因此,二维数组的每一行有n个系数和1个常数b。其实,二维数组存储的是方程组的增广矩阵。n维多元方程组如图所示:

fa0e0d6a8bf5276a3a2ce8e4611154b5.png

二维数组输入完毕之后,程序开始高斯消元法的计算。首先调用search函数,找到绝对值最大的元素,返回到变量position中,position是我自己定义的结构体MAX_POSITION类型,此结构体有两个整形变量x和y,用于存放位置坐标中的横坐标和纵坐标。之后再判断是否需要调用行交换函数和列交换函数。前面这些属于正式高斯消元前的准备工作,因为我们需要找到全主元并调整到主对角线上,所以才会涉及到行交换和列交换。调整好之后,调用Gauss函数,进行消元。因为需要消元n次,所以上述步骤放在一个n重的循环中。最后,调整计算结果的位置,行交换对方程组的计算没有任何影响,但是列交换会改变解的位置。比如说第2列和第四列交换了,那么最终计算出来的x2和x4的结果也应该互换。

二、程序关键语句描述

下面代码是寻找绝对值最大的元素所在位置的函数。现在正对第k个方程进行消元,在消元之前,需要先把剩余方程中系数绝对值最大的元素移动到第k行的主对角线上。假设主对角线的元素就是最大的,如果其余的元素比主对角线的元素还要大,那么就记录下此元素的位置。当所有的系数都遍历了一遍之后,就能找到绝对值最大的元素所在的位置。

MAX_POSITION search(float matrix[][MAX_SIZE + 1], int k,int n) {

int i, j;

MAX_POSITION position;

float max = fabs(matrix[k][k]);

position.x = k;

position.y = k;

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

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

if (fabs(matrix[i][j]) > max) {

max = fabs(matrix[i][j]);

position.x = i;

position.y = j;

}

return position;

}

下面的代码是高斯消元结束之后,把结果往回代入计算的过程。matrix[k][n]是消元之后第k行常数项b的值。同时,它也是xn的解。整个回代过程用两层循环实现,外层循环指的是正在计算第k行,内层循环则是计算xk的具体实现。

//结果回代过程

float temp;//临时变量

for (int k = n - 1; k >= 0; k--) {

temp = matrix[k][n];//临时变量temp赋值常数列b[i];

for (int j = n - 1; j > k; j--) {

temp = temp - matrix[k][j] * x[j];

}

x[k] = temp;

}

下面代码是对计算结果的顺序进行调整,数组order记录着列交换的情况(从第0列开始计数),比如说order数组的内容为{3,0,5,1,4,2},这说明此时的第零列为原先的第三列,此时的第一列为原先的第0列,此时的第二列为原先的第5列,以此列推。此时求解出的x0应为初始输入时的方程组的x3的解,x1应为原先方程组x0的解。因此,在输出结果之前,应该先对结果进行调整。

//对计算结果进行调整,因为之前进行列交换时,改变了计算结果的顺序。

float order_x[MAX_SIZE];//调整之后的结果

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

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

if (i == order[j]) {

order_x[i] = x[j];

break;

}

三、实验结果

选取一个比较特殊的方程组进行测试

d108926045b3dec98ad93dc6ff00ce0b.png

把选主元的代码注释掉,验证选主元对方程组求解的影响

c77c222cbda39b973729811f4bd507b3.png

验证奇异方程的求解问题

cc97767d5602fe45242d3d4814a4ff29.png

验证选主元函数的正确性

912a095aeb951a8197ea56ac90c92e1b.png

四、实验体会

当把选主元的代码给注释掉之后,同样的增广矩阵,程序却运算不出正确的结果了,这说明选主元在某些情形下是有必要的。比如说稀疏的增广矩阵,如果不进行选主元操作,很可能导致计算出非数或者带来较大的误差。但是选主元操作会给程序带来很大的压力,导致时间复杂度和空间复杂度增高,因此,实际应用时,应该根据方程组的实际情况,来确定是否选主元,是选列主元还是全主元。在验证奇异方程的求解问题时,发现出现了不可预知的结果。按照线性代数理论课上的知识,奇异方程的解是不唯一的,也就是说计算结果并不可靠,因此应尽量避免用高斯消去法求解奇异方程组。

最后,上源码,有问题欢迎给我留言。

#include "pch.h"//非VS2017编译器请注释掉此行代码

#include

#include

#define MAX_SIZE 10

int order[MAX_SIZE];//用order[i]标记此时的第i列是原先的第order[i]列

//主元素位置的结构体

struct MAX_POSITION {

int x;

int y;

};

//行交换函数

void raw_swap(float matrix[][MAX_SIZE + 1], int i, int j,int n){

float temp[MAX_SIZE];

int k;

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

temp[k] = matrix[i][k];

matrix[i][k] = matrix[j][k];

matrix[j][k] = temp[k];

}

}

//列交换函数

void colum_swap(float matrix[][MAX_SIZE + 1], int i, int j, int n) {

float temp[MAX_SIZE];

int k = 0;

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

temp[k] = matrix[k][i];

matrix[k][i] = matrix[k][j];

matrix[k][j] = temp[k];

}

//标记第i列和第j列进行过交换

float temp1;

temp1 = order[i];

order[i] = order[j];

order[j] = temp1;

}

//从第k行开始,寻找绝对值最大的元素

MAX_POSITION search(float matrix[][MAX_SIZE + 1], int k,int n) {

int i, j;

MAX_POSITION position;

float max = fabs(matrix[k][k]);

position.x = k;

position.y = k;

for (i = k; i < n; i++)

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

if (fabs(matrix[i][j]) > max) {

max = fabs(matrix[i][j]);

position.x = i;

position.y = j;

}

return position;

}

void Gauss(float matrix[][MAX_SIZE + 1], int k,int n) {//对第k行运用高斯消去法

int i,j;

//第k行的每个系数都除以matrix[k][k]

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

matrix[k][i] = matrix[k][i] / matrix[k][k];

//处理k+1行、k+1列之后的元素

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

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

matrix[i][j] = matrix[i][j] - matrix[k][j] * matrix[i][k];

}

//主对角线元素变为1

matrix[k][k] = 1;

//第k列中,从k+1行开始,后面的元素都变为0

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

matrix[i][k] = 0;

}

int main()

{

float matrix[MAX_SIZE][MAX_SIZE + 1] = { 0 };

int n;

float x[MAX_SIZE] = { 0 };//存放最终方程组的解

MAX_POSITION position;

printf("请输入方程组的个数:");

scanf("%d", &n);

printf("请输入方程组的增广矩阵\n");

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

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

scanf("%f", &matrix[i][j]);

}

//初始化order[i]

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

order[i] = i;

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

position = search(matrix, k, n);//将绝对值最大的元素在数组中的位置存放到position中

//观察选主元结果是否正确↓

printf("现在进行到矩阵的第%d行,当前的全主元为%f\n", k + 1, matrix[position.x][position.y]);

printf("现在输出选主元之前的矩阵\n");

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

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

printf("%f ", matrix[i][j]);

printf("\n");

}

//观察选主元结果是否正确↑

if (k != position.x)//主元素不在当前行

raw_swap(matrix, k, position.x, n);

if (k != position.y)//主元素不在当前列

colum_swap(matrix, k, position.y, n);

//观察选主元结果是否正确↓

printf("现在输出选完主元之后的矩阵\n");

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

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

printf("%f ", matrix[i][j]);

printf("\n");

}

//观察选主元结果是否正确↑

Gauss(matrix, k, n);//进行高斯消元

}

//结果回代过程

float temp;//临时变量

for (int k = n - 1; k >= 0; k--) {

temp = matrix[k][n];//临时变量temp赋值常数列b[i];

for (int j = n - 1; j > k; j--) {

temp = temp - matrix[k][j] * x[j];

}

x[k] = temp;

}

//对计算结果进行调整,因为之前进行列交换时,改变了计算结果的顺序。

float order_x[MAX_SIZE];//调整之后的结果

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

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

if (i == order[j]) {

order_x[i] = x[j];

break;

}

//输出计算结果

printf("现在输出计算结果\n");

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

printf("x%d=%f ", i + 1,order_x[i]);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值