1. C語言實現doolittle演算法解線性方程組
我以前剛好寫過,在我的博客里,你可以去看看
http://hi..com/ycdoit/blog/item/832586b066955d5d082302ef.html
c++解答齊次方程組的幾種方法——Cramer,Gauss列主元,Gauss全主元,Doolittle演算法/
/解線性方程組
//By JJ,2008
#include<iostream.h>
#include<iomanip.h>
#include<stdlib.h>
//----------------------------------------------全局變數定義區
const int Number=15; //方程最大個數
double a[Number][Number],b[Number],_a[Number][Number],_b[Number]; //系數行列式
int A_y[Number]; //a[][]中隨著橫坐標增加列坐標的排列順序,如a[0][0],a[1][2],a[2][1]...則A_y[]={0,2,1...};
int lenth,_lenth; //方程的個數
double a_sum; //計算行列式的值
char * x; //未知量a,b,c的載體
//----------------------------------------------函數聲明區
void input(); //輸入方程組
void print_menu(); //列印主菜單
int choose (); //輸入選擇
void cramer(); //Cramer演算法解方程組
void gauss_row(); //Gauss列主元解方程組
void guass_all(); //Gauss全主元解方程組
void Doolittle(); //用Doolittle演算法解方程組
int Doolittle_check(double a[][Number],double b[Number]); //判斷是否行列式>0,若是,調整為順序主子式全>0
void xiaoqu_u_l(); //將行列式Doolittle分解
void calculate_u_l(); //計算Doolittle結果
double & calculate_A(int n,int m); //計算行列式
double quanpailie_A(); //根據列坐標的排列計算的值,如A_y[]={0,2,1},得sum=a[0][ A_y[0] ] * a[1][ A_y[1] ] * a[2][ A_y[2] ]=a[0][0]*a[1][2]*a[2][1];
void exchange(int m,int i); //交換A_y[m],A_y[i]
void exchange_lie(int j); //交換a[][j]與b[];
void exchange_hang(int m,int n); //分別交換a[][]和b[]中的m與n兩行
void gauss_row_xiaoqu(); //Gauss列主元消去法
void gauss_all_xiaoqu(); //Gauss全主元消去法
void gauss_calculate(); //根據Gauss消去法結果計算未知量的值
void exchange_a_lie(int m,int n); //交換a[][]中的m和n列
void exchange_x(int m,int n); //交換x[]中的x[m]和x[n]
void recovery(); //恢復數據
//主函數
void main()
{
int flag=1;
input(); //輸入方程
while(flag)
{
print_menu(); //列印主菜單
flag=choose(); //選擇解答方式
}
}
//函數定義區
void print_menu()
{
system("cls");
cout<<"------------方程系數和常數矩陣表示如下:\n";
for(int j=0;j<lenth;j++)
cout<<"系數"<<j+1<<" ";
cout<<"\t常數";
cout<<endl;
for(int i=0;i<lenth;i++)
{
for(j=0;j<lenth;j++)
cout<<setw(8)<<setiosflags(ios::left)<<a[i][j];
cout<<"\t"<<b[i]<<endl;
}
cout<<"-----------請選擇方程解答的方案----------";
cout<<"\n 1. 克拉默(Cramer)法則";
cout<<"\n 2. Gauss列主元消去法";
cout<<"\n 3. Gauss全主元消去法";
cout<<"\n 4. Doolittle分解法";
cout<<"\n 5. 退出";
cout<<"\n 輸入你的選擇:";
}
void input()
{ int i,j;
cout<<"方程的個數:";
cin>>lenth;
if(lenth>Number)
{
cout<<"It is too big.\n";
return;
}
x=new char[lenth];
for(i=0;i<lenth;i++)
x[i]='a'+i;
//輸入方程矩陣
//提示如何輸入
cout<<"====================================================\n";
cout<<"請在每個方程里輸入"<<lenth<<"系數和一個常數:\n";
cout<<"例:\n方程:a";
for(i=1;i<lenth;i++)
{
cout<<"+"<<i+1<<x[i];
}
cout<<"=10\n";
cout<<"應輸入:";
for(i=0;i<lenth;i++)
cout<<i+1<<" ";
cout<<"10\n";
cout<<"==============================\n";
//輸入每個方程
for(i=0;i<lenth;i++)
{
cout<<"輸入方程"<<i+1<<":";
for(j=0;j<lenth;j++)
cin>>a[i][j];
cin>>b[i];
}
//備份數據
for(i=0;i<lenth;i++)
for(j=0;j<lenth;j++)
_a[i][j]=a[i][j];
for(i=0;i<lenth;i++)
_b[i]=b[i];
_lenth=lenth;
}
//輸入選擇
int choose()
{
int choice;char ch;
cin>>choice;
switch(choice)
{
case 1:cramer();break;
case 2:gauss_row();break;
case 3:guass_all();break;
case 4:Doolittle();break;
case 5:return 0;
default:cout<<"輸入錯誤,請重新輸入:";
choose();
break;
}
cout<<"\n是否換種方法求解(Y/N):";
cin>>ch;
if(ch=='n'||ch=='N') return 0;
recovery();
cout<<"\n\n\n";
return 1;
}
//用克拉默法則求解方程.
void cramer()
{
int i,j;double sum,sum_x;char ch;
//令第i行的列坐標為i
cout<<"用克拉默(Cramer)法則結果如下:\n";
for(i=0;i<lenth;i++)
A_y[i]=i;
sum=calculate_A(lenth,0);
if(sum!=0)
{
cout<<"系數行列式不為零,方程有唯一的解:";
for(i=0;i<lenth;i++)
{ ch='a'+i;
a_sum=0;
for(j=0;j<lenth;j++)
A_y[j]=j;
exchange_lie(i);
sum_x=calculate_A(lenth,0);
cout<<endl<<ch<<"="<<sum_x/sum;
exchange_lie(i);
}
}
else
{
cout<<"系數行列式等於零,方程沒有唯一的解.";
}
cout<<"\n";
}
double & calculate_A(int n,int m) //計算行列式
{ int i;
if(n==1) {
a_sum+= quanpailie_A();
}
else{for(i=0;i<n;i++)
{ exchange(m,m+i);
calculate_A(n-1,m+1);
exchange(m,m+i);
}
}
return a_sum;
}
double quanpailie_A() //計算行列式中一種全排列的值
{
int i,j,l;
double sum=0,p;
for(i=0,l=0;i<lenth;i++)
for(j=0;A_y[j]!=i&&j<lenth;j++)
if(A_y[j]>i) l++;
for(p=1,i=0;i<lenth;i++)
p*=a[i][A_y[i]];
sum+=p*((l%2==0)?(1):(-1));
return sum;
}
//高斯列主元排列求解方程
void gauss_row()
{
int i,j;
gauss_row_xiaoqu(); //用高斯列主元消區法將系數矩陣變成一個上三角矩陣
for(i=0;i<lenth;i++)
{
for(j=0;j<lenth;j++)
cout<<setw(10)<<setprecision(5)<<a[i][j];
cout<<setw(10)<<b[i]<<endl;
}
if(a[lenth-1][lenth-1]!=0)
{
cout<<"系數行列式不為零,方程有唯一的解:\n";
gauss_calculate();
for(i=0;i<lenth;i++) //輸出結果
{
cout<<x[i]<<"="<<b[i]<<"\n";
}
}
else
cout<<"系數行列式等於零,方程沒有唯一的解.\n";
}
void gauss_row_xiaoqu() //高斯列主元消去法
{
int i,j,k,maxi;double lik;
cout<<"用Gauss列主元消去法結果如下:\n";
for(k=0;k<lenth-1;k++)
{
j=k;
for(maxi=i=k;i<lenth;i++)
if(a[i][j]>a[maxi][j]) maxi=i;
if(maxi!=k)
exchange_hang(k,maxi);//
for(i=k+1;i<lenth;i++)
{
lik=a[i][k]/a[k][k];
for(j=k;j<lenth;j++)
a[i][j]=a[i][j]-a[k][j]*lik;
b[i]=b[i]-b[k]*lik;
}
}
}
//高斯全主元排列求解方程
void guass_all()
{
int i,j;
gauss_all_xiaoqu();
for(i=0;i<lenth;i++)
{
for(j=0;j<lenth;j++)
cout<<setw(10)<<setprecision(5)<<a[i][j];
cout<<setw(10)<<b[i]<<endl;
}
if(a[lenth-1][lenth-1]!=0)
{
cout<<"系數行列式不為零,方程有唯一的解:\n";
gauss_calculate();
for(i=0;i<lenth;i++) //輸出結果
{
for(j=0;x[j]!='a'+i&&j<lenth;j++);
cout<<x[j]<<"="<<b[j]<<endl;
}
}
else
cout<<"系數行列式等於零,方程沒有唯一的解.\n";
}
void gauss_all_xiaoqu() //Gauss全主元消去法
{
int i,j,k,maxi,maxj;double lik;
cout<<"用Gauss全主元消去法結果如下:\n";
for(k=0;k<lenth-1;k++)
{
for(maxi=maxj=i=k;i<lenth;i++)
{
for(j=k;j<lenth;j++)
if(a[i][j]>a[maxi][ maxj])
{ maxi=i;
maxj=j;
}
}
if(maxi!=k)
exchange_hang(k,maxi);
if(maxj!=k)
{
exchange_a_lie(maxj,k); //交換兩列
exchange_x(maxj,k);
}
for(i=k+1;i<lenth;i++)
{
lik=a[i][k]/a[k][k];
for(j=k;j<lenth;j++)
a[i][j]=a[i][j]-a[k][j]*lik;
b[i]=b[i]-b[k]*lik;
}
}
}
void gauss_calculate() //高斯消去法以後計算未知量的結果
{
int i,j;double sum_ax;
b[lenth-1]=b[lenth-1]/a[lenth-1][lenth-1];
for(i=lenth-2;i>=0;i--)
{
for(j=i+1,sum_ax=0;j<lenth;j++)
sum_ax+=a[i][j]*b[j];
b[i]=(b[i]-sum_ax)/a[i][i];
}
}
void Doolittle() //Doolittle消去法計算方程組
{
double temp_a[Number][Number],temp_b[Number];int i,j,flag;
for(i=0;i<lenth;i++)
for(j=0;j<lenth;j++)
temp_a[i][j]=a[i][j];
flag=Doolittle_check(temp_a,temp_b);
if(flag==0) cout<<"\n行列式為零.無法用Doolittle求解.";
xiaoqu_u_l();
calculate_u_l();
cout<<"用Doolittle方法求得結果如下:\n";
for(i=0;i<lenth;i++) //輸出結果
{
for(j=0;x[j]!='a'+i&&j<lenth;j++);
cout<<x[j]<<"="<<b[j]<<endl;
}
}
void calculate_u_l() //計算Doolittle結果
{ int i,j;double sum_ax=0;
for(i=0;i<lenth;i++)
{
for(j=0,sum_ax=0;j<i;j++)
sum_ax+=a[i][j]*b[j];
b[i]=b[i]-sum_ax;
}
for(i=lenth-1;i>=0;i--)
{
for(j=i+1,sum_ax=0;j<lenth;j++)
sum_ax+=a[i][j]*b[j];
b[i]=(b[i]-sum_ax)/a[i][i];
}
}
void xiaoqu_u_l() //將行列式按Doolittle分解
{ int i,j,n,k;double temp;
for(i=1,j=0;i<lenth;i++)
a[i][j]=a[i][j]/a[0][0];
for(n=1;n<lenth;n++)
{ //求第n+1層的上三角矩陣部分即U
for(j=n;j<lenth;j++)
{ for(k=0,temp=0;k<n;k++)
temp+=a[n][k]*a[k][j];
a[n][j]-=temp;
}
for(i=n+1;i<lenth;i++) //求第n+1層的下三角矩陣部分即L
{ for(k=0,temp=0;k<n;k++)
temp+=a[i][k]*a[k][n];
a[i][n]=(a[i][n]-temp)/a[n][n];
}
}
}
int Doolittle_check(double temp_a[][Number],double temp_b[Number]) //若行列式不為零,將系數矩陣調整為順序主子式大於零
{
int i,j,k,maxi;double lik,temp;
for(k=0;k<lenth-1;k++)
{
j=k;
for(maxi=i=k;i<lenth;i++)
if(temp_a[i][j]>temp_a[maxi][j]) maxi=i;
if(maxi!=k)
{ exchange_hang(k,maxi);
for(j=0;j<lenth;j++)
{ temp=temp_a[k][j];
temp_a[k][j]=temp_a[maxi][j];
temp_a[maxi][j]=temp;
}
}
for(i=k+1;i<lenth;i++)
{
lik=temp_a[i][k]/temp_a[k][k];
for(j=k;j<lenth;j++)
temp_a[i][j]=temp_a[i][j]-temp_a[k][j]*lik;
temp_b[i]=temp_b[i]-temp_b[k]*lik;
}
}
if(temp_a[lenth-1][lenth-1]==0) return 0;
return 1;
}
void exchange_hang(int m,int n) //交換a[][]中和b[]兩行
{
int j; double temp;
for(j=0;j<lenth;j++)
{ temp=a[m][j];
a[m][j]=a[n][j];
a[n][j]=temp;
}
temp=b[m];
b[m]=b[n];
b[n]=temp;
}
void exchange(int m,int i) //交換A_y[m],A_y[i]
{ int temp;
temp=A_y[m];
A_y[m]=A_y[i];
A_y[i]=temp;
}
void exchange_lie(int j) //交換未知量b[]和第i列
{ double temp;int i;
for(i=0;i<lenth;i++)
{ temp=a[i][j];
a[i][j]=b[i];
b[i]=temp;
}
}
void exchange_a_lie(int m,int n) //交換a[]中的兩列
{ double temp;int i;
for(i=0;i<lenth;i++)
{ temp=a[i][m];
a[i][m]=a[i][n];
a[i][n]=temp;
}
}
void exchange_x(int m,int n) //交換未知量x[m]與x[n]
{ char temp;
temp=x[m];
x[m]=x[n];
x[n]=temp;
}
void recovery() //用其中一種方法求解後恢復數據以便用其他方法求解
{
for(int i=0;i<lenth;i++)
for(int j=0;j<lenth;j++)
a[i][j]=_a[i][j];
for(i=0;i<lenth;i++)
b[i]=_b[i];
for(i=0;i<lenth;i++)
x[i]='a'+i;
a_sum=0;
lenth=_lenth;
}
2. C語言程序解線性方程組
給,下面的代碼已經編譯運行確認,肯定好用了,試試吧:)
#include<conio.h>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define NUMBER 20
#define Esc 0x1b
#define Enter 0x0d
float A[NUMBER][NUMBER+1] ,ark;
int flag,n;
void exchange(int r,int k);
float max(int k);
void message();
int main()
{
float x[NUMBER]; /*此數組用於存放方程解*/
int k,i,j;
char celect;
system("cls");
printf("\n用Gauss列主元消元法解線性方程組");
printf("\n1.解方程組請按Enter.");
printf("\n2.退出程式請按Esc.");
celect=getch();
if(celect==Esc)
exit(0);
printf("\n 輸入方程組的維數:n=");
scanf("%d",&n);
printf("\n現在輸入系數矩陣A和向量b:");
for(i=1;i<=n;i++)
{
printf("\n請輸入a%d1--a%d%d系數和向量b%d: \n",i,i,n,i);
/*實現將每一行中的系數和向量一次性輸入,數之間用空格格開,輸完後回車確定*/
for(j=1;j<=n+1;j++) /*將剛才輸入的數存入數組*/
scanf("%f",&A[i][j]);
}
for(k=1;k<=n-1;k++)
{
ark=max(k);
if(ark==0) /*判斷方程是否為線性方程,即是否合法*/
{
printf("\n此方程組不合法!");message();
}
else if(flag!=k)
exchange(flag,k);
for(i=k+1;i<=n;i++)
for(j=k+1;j<=n+1;j++)
A[i][j]=A[i][j]-A[k][j]*A[i][k]/A[k][k];
}
x[n]=A[n][n+1]/A[n][n];
for( k=n-1;k>=1;k--)
{
float me=0;
for(j=k+1;j<=n;j++)
{
me=me+A[k][j]*x[j];
}
x[k]=(A[k][n+1]-me)/A[k][k];
}
for(i=1;i<=n;i++)
{
printf("\nx%d=%f",i,x[i]);
}
message();
getch();
return 1;
}
void exchange(int r,int k) /*交換行的矩函數*/
{
int i;
for(i=1;i<=n+1;i++)
A[0][i]=A[r][i];
for(i=1;i<=n+1;i++)
A[r][i]=A[k][i];
for(i=1;i<=n+1;i++)
A[k][i]=A[0][i];
}
float max(int k) /*比校系數大小的函數*/
{
int i;
float temp=0;
for(i=k;i<=n;i++)
if(fabs(A[i][k])>temp)
{
temp=fabs(A[i][k]);
flag=i;
}
return temp;
}
void message() /*實現菜單選擇的函數*/
{
printf("\n 繼續運算按 Enter ,退出程式按 Esc!");
switch(getch())
{
case Enter: main();
case Esc: exit(0);
default:{printf("\n不合法的輸入!");message();}
}
}