手动解线性方程组有两种方法。
1.通过消元求解
2.通过矩阵行列式等来求解
我们现在要用c语言来实现用行列式求解线性方程组。在求解之前我们首先要学习行列式相关知识,如果不了解行列式请先去百度行列式进行学习,记得回来哦~
可以发现行列式的数字排法很像二维数组的排法,于是我们用二维数组保存行列式内容。所以我们只需要把输入的数据存入二维数组内。
因为数组的大小在定义的时候必须是确定的,而我们可能要算二元一次方程组,我们有四个数据,也可能是三元的我们有九个数据,于是二元的需要定义一个a[2][2],三元的我们要定义一个a[3][3]。这不是一个确定的数,所以我们要才用一种特殊的方式(动态内存分配)。这样就能产生一个动态的数组。
代码如下:
//从输入的数据中存到数组内
double* getArrFromDet(int n)
{
double num;
double* p = (double*)calloc(1, sizeof(double) * n * n);
if (!p)return -1;
int i = 0;
while (n * n != i)
{
scanf("%lf", &num);
*(p + i) = num;
i++;
}
return p;
}
现在我们剩下的问题就是计算数组里面的行列式的值。
我们学过计算行列式有一种方法,叫做拉普拉斯定理。拉普拉斯定理,计算降阶行列式的一种方法。该定理断言:在n阶行列式D=|aij| 中,任意取定k行(列),1≤k≤n-1,由这k行(列)的元素所构成的一切k阶子式与其代数余子式的乘积的和等于行列式D的值。此展式称为拉普拉斯展式。
于是我们就运用这个定理,我们运用第一行的各元素乘以对于的各元素的代数余子式。代数余子式又是一个行列式继续用这个方法,一直到最后只剩下一个就返还这个的值。这像不像是个递归,那我们就用递归来解决这个问题吧
哦~对了好像没告诉你们代数余子式怎么求。现在我们来讲一讲他的求法。
只需要把选定的这个元素的行,和列全部去除,组成的行列式就是余子式,然后代数余子式就是有±号,比如说在第1行第1列的元素的代数余子式就是1×余子式,而第1行第2列的元素就是-1×余子式,是不是能发现什么规律,就是(-1)∧(行+列)×行列式就可以了。好了这个懂了
就来看代码吧。
递归结束条件,只剩下一个元素在行列式中。
//将数组进行行列计算
double calDet(double *arr,int n)
{
int i = 0;
double sum = 0;
if (n == 1)
{
return *arr;
}
else
{
while (i < n)
{
double* arrTemp = (double*)calloc(1, sizeof(double) * (n - 1) * (n - 1));
double* temp = arrTemp;
//去除正在递归的该行列的
for (int k =1; k < n; k++)
{
for (int j = 0; j < n; j++)
{
if (j != i)
{
*temp = *((arr + k * n) + j);
temp++;
}
}
}
sum += pow(-1,i)*(*(arr + i) * calDet(arrTemp, n - 1));//递归调用
i++;
}
}
return sum;
}
现在我们会求行列式了,那问题只剩下一个了:计算多个行列式的值并保存下来然后再运用克拉默法则运算出方程组的解。具体代码如下:
//求解线性方程组
void solveEqu(int n)
{
double value[127] = { 0 };
//获取d的值
printf("d=");
value[0] = calDet(getArrFromDet(n), n);
int i = 1;
while (i != n + 1)
{
printf("d%d=", i);
value[i] = calDet(getArrFromDet(n), n);
i++;
}
//输出方程的解
i = 1;
while (i != n + 1)
{
if (value[0] == 0 && value[i] != 0)
{
printf("方程无解");
break;
}
else
{
printf("x%d = %lf\n", i, value[i] / value[0]);
i++;
}
}
}
这样我们就能解出一个线性方程组。
接下来让我们看看这个简单的主函数吧
int main()
{
int n;
printf("输入方程组的元数");
scanf("%d", &n);
solveEqu(n);
while (1);
return 0;
}
对了,再加上主函数
#include<stdio.h>
在用用高斯消元解法
完整代码如下:
#include <stdio.h>
#include <math.h>
#define MAX 20
void swap(double* a,double*b){
double tmp = *a;
*a = *b;
*b = tmp;
}
void swapArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++)
swap(&a[i],&b[i]);
}
double computeDet(double array[MAX][MAX], int n){
// 通过初等行变换,再计算对角元素乘积,来计算行列式的值
int i,j,k;
int sign=0; //行列式交换一次需要改变符号,此变量记录交换次数
double sum=1.0; //结果
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
sign++;
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
for(i=0;i<n;i++)
sum *= array[i][i];
if(sign%2!=0) //交换偶数次符仍为正
sum *= -1;
return sum;
}
void rowTrans(double array[MAX][MAX], int n){
// 做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void rowTrans_Ab(double array[MAX][MAX], int n){
// 做A、b同时做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n+1);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<=n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void printMatrix(double array[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%lf",array[i][j]);
if(j==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
}
void printArray(double x[MAX], int n){
int i;
for(i=0;i<n;i++){
printf("%lf",x[i]);
if(i==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
void copyMatrix(double a[MAX][MAX], double b[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;i++){
b[i][j]=a[i][j];
}
}
}
void copyArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++){
b[i]=a[i];
}
}
void solveLowerEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为下三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=0;i<n;i++){
for(j=0;j<i;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
void solveUpperEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为上三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=n-1;i>=0;i--){
for(j=i+1;j<n;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
//解一般方程
int main(){
int i,j;
int n; //阶数
double tmp; //临时变量
double x[MAX]; //未知数矩阵
double b[MAX]; //常系数矩阵
double A[MAX][MAX]; //系数矩阵
//数据初始化
printf("Please enter the dimensions of the coefficient matrix:(n)");
scanf("%d",&n);
printf("Please enter the value of coefficient matrix:(A)\n");
for(i=0;i<n;i++){
for(j=0;j<n;j++)
scanf("%lf",&A[i][j]);
}
printf("Please enter the value of the constant term matrix:(b)\n");
for(i=0;i<n;i++){
scanf("%lf",&b[i]);
}
//初始化x和Ab
for(i=0;i<n;i++){
x[i]=0.0;
A[i][n]=b[i];
}
//对矩阵A做初等行变换
rowTrans_Ab(A,n);
printf("rowTrans:\n");
printMatrix(A,n);
//取变化后的b
for(i=0;i<n;i++){
b[i]=A[i][n];
}
//解上三角矩阵
solveUpperEquations(A,x,b,n);
//输出结果
printf("The result are:\n");
printArray(x,n);
return 0;
}
还有Cholesky法求正定对称矩阵的线性方程组
完整代码如下:
#include <stdio.h>
#include <math.h>
#define MAX 20
void swap(double* a,double*b){
double tmp = *a;
*a = *b;
*b = tmp;
}
void swapArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++)
swap(&a[i],&b[i]);
}
double computeDet(double array[MAX][MAX], int n){
// 通过初等行变换,再计算对角元素乘积,来计算行列式的值
int i,j,k;
int sign=0; //行列式交换一次需要改变符号,此变量记录交换次数
double sum=1.0; //结果
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
sign++;
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
for(i=0;i<n;i++)
sum *= array[i][i];
if(sign%2!=0) //交换偶数次符仍为正
sum *= -1;
return sum;
}
void rowTrans(double array[MAX][MAX], int n){
// 做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void rowTrans_Ab(double array[MAX][MAX], int n){
// 做A、b同时做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n+1);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<=n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void printMatrix(double array[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%lf",array[i][j]);
if(j==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
}
void printArray(double x[MAX], int n){
int i;
for(i=0;i<n;i++){
printf("%lf",x[i]);
if(i==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
void copyMatrix(double a[MAX][MAX], double b[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;i++){
b[i][j]=a[i][j];
}
}
}
void copyArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++){
b[i]=a[i];
}
}
void transpose(double a[MAX][MAX], int n){
int i,j;
for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
swap(&a[i][j], &a[j][i]);
}
}
}
void solveLowerEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为下三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=0;i<n;i++){
for(j=0;j<i;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
void solveUpperEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为上三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=n-1;i>=0;i--){
for(j=i+1;j<n;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
int main(){
int i,j;
int n; //阶数
double tmp; //临时变量
double x[MAX]; //未知数矩阵
double A[MAX][MAX]; //系数矩阵
double b[MAX]; //常系数矩阵
//数据初始化
printf("Please enter the dimensions of the coefficient matrix:(n)");
scanf("%d",&n);
printf("Please enter the value of coefficient matrix:(A)\n");
for(i=0;i<n;i++){
for(j=0;j<n;j++)
scanf("%lf",&A[i][j]);
}
printf("Please enter the value of the constant term matrix:(b)\n");
for(i=0;i<n;i++){
scanf("%lf",&b[i]);
}
for(i=0;i<n;i++){
x[i]=0.0;
}
//对矩阵A做初等行变换
rowTrans(A,n);
printf("rowTrans:\n");
printMatrix(A,n);
//处理主元,得到L.T(上三角矩阵)
for(i=0;i<n;i++){
if(A[i][i]<0){
for(j=i;j<n;j++){
A[i][j]*=-1;
}
}
if(A[i][i]!=1){
tmp=sqrt(A[i][i]);
for(j=i;j<n;j++){
A[i][j]/=tmp;
}
}
}
printf("L.T:\n");
printMatrix(A,n);
//求得L(下三角矩阵),求解第一步方程Ly=b,求得y
transpose(A,n);
printf("L:\n");
printMatrix(A,n);
solveLowerEquations(A,x,b,n);
printf("y:\n");
printArray(x,n);
//求得L.T(上三角矩阵),求解第二步方程L.T*x=y,求得x
transpose(A,n);
copyArray(x,b,n);//x中暂存的y赋给b
solveUpperEquations(A,x,b,n);
printf("The result are:\n");
printArray(x,n);
return 0;
//期望结果:(1,-1,0,2,1,-1,0,2)
}