1.声明与全局变量
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define N 10//限制计算的最大阶数
double A[N][N];
double B[N];
double arr[N] = { 0.0 };
int n;//要计算方程的阶数
2.要实现的功能
int main()
{
// 输入
my_scanf();
// 排序,消元
for (int NUM = 0; NUM < n; NUM++)
{
sorting(NUM);
print();
elimination(NUM);
print();
}
print();
// 计算结果
result();
// 打印结果
for (int i = 0; i < n; i++)
{
printf("第%d个解为%.4lf",i+1, arr[i]);
}
return 0;
}
3.各个模块的实现
1.输入的实现
void my_scanf()
{
//输入阶数
printf("输入数组的阶数:");
scanf("%d", &n);
//外层循环代表行,内层循环代表列,可以一行输入完后再输入下一行
for (int i = 0; i < n; i++)
{
printf("请输入第%d行的%d个元素,输入完后回车\n", i + 1, n);
for (int j = 0; j < n; j++)
{
scanf("%lf", &A[i][j]);
}
}
//输入方程等号右边对应的n个数
printf("输入右端的%d个数\n", n);
for (int i = 0; i < n; i++)
{
scanf("%lf", &B[i]);
}
//打印
printf("您输入的数组为\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%.4lf ", A[i][j]);
}
printf("| %.4lf", B[i]);
printf("\n");
}
}
2.排序的实现
排序是为了选取主元放在第一列便于消元,这里用到了冒泡排序。先认为NUM第一次为0
void sorting(int NUM)
{
//外面的i是为了执行多少次整体流程
for (int i = NUM; i < n - 1; i++)
{
//j代表行,p代表列,jp所代表的就是一个元素
for (int j = NUM; j < n - i - 1; j++)
{
//if是为了比较两行的首元素的大小,从而判断是否执行交换
if (A[j][NUM] < A[j + 1][NUM])
{
//为了实现交换,p代表列,当j在这个循环内为定值时,p++可以让每行的各个元素依次交换
for (int p = NUM; p < n; p++)
{
double temp = A[j][p];
A[j][p] = A[j + 1][p];
A[j + 1][p] = temp;
}
double temp = B[j];
B[j] = B[j + 1];
B[j + 1] = temp;
}
}
}
}
这里附上一张图来解释一下冒泡排序在数组中的应用
!!for循环执行次数的问题
显而易见如果阶数为n则整个程序要执行n-1次,一个流程里要交换n-i-1次,而p执行的次数是由一行有多少个元素决定的每个元素都要换,所以执行次数等于n
再看回主函数中的for循环,传入了一个变量NUM
for (int NUM = 0; NUM < n; NUM++)
{
sorting(NUM);
print();
elimination(NUM);
print();
}
这里的目的是让圈层逐渐缩小 ,显然我们在消元(消元函数待会讲)过后第一列的其它元素都已经变为了0,这次我们要让其从第二列第二行开始与下面的元素比较从而进行排序。所以在sorting函数里层的两个循环中我把j和p赋值为NUM。然后由于少了一行,那么i也要赋值为NUM,从而达到少操作一次的目的。
3.消元的实现(elimination)
void elimination(int NUM)
{
for (int i = NUM + 1; i < n; i++)
{
if (A[i][NUM] != 0)//用于判断该次的首元素是否为0,以避免除以0的情况
{
double a = A[NUM][NUM] / A[i][NUM];
for (int j = NUM; j < n; j++)
{
A[i][j] = A[NUM][j] - A[i][j] * a;
}
B[i] = B[NUM] - B[i] * a;
}
}
}
这里我们依旧要传入一个NUM与sorting里面NUM的功能相似,但主元所处的那一行是不用消元的 而i又作为数组的行,所以我们要将i的初始值赋为NUM+1,里层的if用于判断被消行的首元素是否为0,从而避免除以0的情况(如果是0就不用消了),然后我们将 A[NUM][NUM] / A[i][NUM]赋给一个double a,这里不直接把里层for循环里的a替换成A[NUM][NUM] / A[i][NUM],原因A[i][NUM]在第一次循环中被改变,就不是原来的值了,从而导致错误,所以我们先用一个a变量把A[NUM][NUM] / A[i][NUM]的值储存起来,里层for循环里(A[i][j] = A[NUM][j] - A[i][j] * a;)就是常规消元步骤,显而易见。由于最右边的B[i]只用消一次,所以我把它放在里循环的外头
4.计算结果的函数
void result()
{
for (int i = 1; i <= n; i++)//外层for是用来循环n次
{
double temp = B[n - i];
for (int j = 1; j <= i; j++)//从右向左访问数组元素的个数不能大于i
{
temp -= A[n - i][n - j] * arr[n - j];
}
arr[n - i] = temp / A[n - i][n - i];
}
}
我最初创建了一个arr数组,这时就派上用场了 ,double temp = B[n - i];在里循环外头赋值和上面讲的一样都是为了避免在里循环里头值被改变导致结果错误
如何求解想必大家都知道,的由图中公式推导可知道temp -= A[n - i][n - j] * arr[n - j];会有首元素的出现,可我们本不该减去首元素,但不用担心,每次首元素都是与0相乘,例如A[n-1][n-1]*arr[n-1],这里arr[n-1]等于0,所以不用担心首元素被减去的情况。
关于j的取值:从下往上被减元素依次增加且等于i,所以只要让j<=i即可
最后里循环里头的表达式是分子,这个表示式arr[n - i] = temp / A[n - i][n - i];是让分子除以分母得到结果(这里的值如果不是整数是不精确的近似值,我当时想的是用分数的形式表达,但是不太好实现,有待开发)
5.最后一个很简单的print函数
void print()
{
printf("交换后的数组\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%.4lf ", A[i][j]);
}
printf("| %.4lf", B[i]);
printf("\n");
}
}
两个for循环依次打印就好了。
4.最后把代码组合起来
适用范围,有解的方程
#include <stdio.h>
#define N 10
double A[N][N];
double B[N];
double arr[N] = { 0.0 };
int n;
void my_scanf()
{
printf("输入数组的阶数:");
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
printf("请输入第%d行的%d个元素,输入完后回车\n", i + 1, n);
for (int j = 0; j < n; j++)
{
scanf("%lf", &A[i][j]);
}
}
printf("输入右端的%d个数\n", n);
for (int i = 0; i < n; i++)
{
scanf("%lf", &B[i]);
}
//打印
printf("您输入的数组为\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%.4lf ", A[i][j]);
}
printf("| %.4lf", B[i]);
printf("\n");
}
}
void sorting(int NUM)
{
//外面的i是为了执行多少次整体流程
for (int i = NUM; i < n - 1; i++)
{
//j代表行,p代表列,jp所代表的就是一个元素
for (int j = NUM; j < n - i - 1; j++)
{
//if是为了比较两行的首元素的大小,从而判断是否执行交换
if (A[j][NUM] < A[j + 1][NUM])
{
//为了实现交换,p代表列,当j在这个循环内为定值时,p++可以让每行的各个元素依次交换
for (int p = NUM; p < n; p++)
{
double temp = A[j][p];
A[j][p] = A[j + 1][p];
A[j + 1][p] = temp;
}
double temp = B[j];
B[j] = B[j + 1];
B[j + 1] = temp;
}
}
}
}
void print()
{
printf("交换后的数组\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%.4lf ", A[i][j]);
}
printf("| %.4lf", B[i]);
printf("\n");
}
}
void elimination(int NUM)
{
for (int i = NUM + 1; i < n; i++)
{
if (A[i][NUM] != 0)//用于判断该次的首元素是否为0,以避免除以0的情况
{
double a = A[NUM][NUM] / A[i][NUM];
for (int j = NUM; j < n; j++)
{
A[i][j] = A[NUM][j] - A[i][j] * a;
}
B[i] = B[NUM] - B[i] * a;
}
}
}
void result()
{
for (int i = 1; i <= n; i++)//外层for是用来循环n次
{
double temp = B[n - i];
for (int j = 1; j <= i; j++)
{
temp -= A[n - i][n - j] * arr[n - j];
}
arr[n - i] = temp / A[n - i][n - i];
}
}
int main()
{
// 输入
my_scanf();
// 排序,消元
for (int NUM = 0; NUM < n; NUM++)
{
sorting(NUM);
print();
elimination(NUM);
print();
}
print();
// 计算结果
result();
// 打印结果
for (int i = 0; i < n; i++)
{
printf("第%d个解为%.4lf",i+1, arr[i]);
}
return 0;
}
更高级,且精确的方法有待开发……