原文链接:http://blog.csdn.net/zhangxaochen/article/details/8020668
书上的例程:
看这里: http://is.gd/VoBVUJ
void NR::gaussj(Mat_IO_DP &a, Mat_IO_DP &b){ int i,icol,irow,j,k,l,ll; DP big,dum,pivinv; int n=a.nrows(); int m=b.ncols(); Vec_INT indxc(n),indxr(n),ipiv(n); for (j=0;j<n;j++) ipiv[j]=0; for (i=0;i<n;i++) { big=0.0; for (j=0;j<n;j++){ if (ipiv[j] != 1){ for (k=0;k<n;k++) { if (ipiv[k] == 0) { if (fabs(a[j][k]) >= big) { big=fabs(a[j][k]); irow=j; icol=k; } } } } } ++(ipiv[icol]); if (irow != icol) { for (l=0;l<n;l++) SWAP(a[irow][l],a[icol][l]); for (l=0;l<m;l++) SWAP(b[irow][l],b[icol][l]); } indxr[i]=irow; indxc[i]=icol; if (a[icol][icol] == 0.0) nrerror("gaussj: Singular Matrix"); pivinv=1.0/a[icol][icol]; //a[icol][icol]=1.0; for (l=0;l<n;l++) a[icol][l] *= pivinv; for (l=0;l<m;l++) b[icol][l] *= pivinv; for (ll=0;ll<n;ll++){ if (ll != icol) { dum=a[ll][icol]; //a[ll][icol]=0.0; for (l=0;l<n;l++) a[ll][l] -= a[icol][l]*dum; for (l=0;l<m;l++) b[ll][l] -= b[icol][l]*dum; } } } for (l=n-1;l>=0;l--) { if (indxr[l] != indxc[l]) for (k=0;k<n;k++) SWAP(a[k][indxr[l]],a[k][indxc[l]]); } }
上面的代码,反正我是觉得很难明白。有两处地方绕了一下,好像故意逗你玩。。
于是自己又写了一遍:(因为手上用的vs2010,构造矩阵的时候不支持二维数组uniform initialization,为了传参方便,所以函数定义成了 “double a[][3]” 这么丑的样子)
void myGaussj(double a[][3], double b[][1], int n, int m){ vector<bool> dirty(n); double tmp; int row, col; for(int re=0; re<n; re++){ for(int i=0; i<n; i++){ if(true==dirty[i]) continue; double big=0; // 找到一行内最大的: for(int j=0; j<n; j++){ if( (tmp=fabs(a[i][j]))>big){ big=tmp; row=i; col=j; } } assert(big!=0); // 如果big不在对角线,行交换到对角线上 dirty[col]=true; //准备开搞 if(row!=col){ for(int c=0; c<n; c++){ tmp=a[row][c]; a[row][c]=a[col][c]; a[col][c]=tmp; } for(int c=0; c<m; c++){ tmp=b[row][c]; b[row][c]=b[col][c]; b[col][c]=tmp; } }// if row!=col //主元归一 tmp=a[col][col]; for(int c=0; c<n; c++){ a[col][c]*=1.0/tmp; } for(int c=0; c<m; c++){ b[col][c]*=1.0/tmp; } //col 列 其他行归零,当然行内的其他列也减掉对应值 for(int r=0; r<n; r++){ if(r==col) continue; tmp=a[r][col]; for(int c=0; c<n; c++){ a[r][c]-=tmp*a[col][c]; } for(int c=0; c<m; c++){ b[r][c]-=tmp*b[col][c]; } } break; }// for i }// for re }
基本步骤就是, 对于每一行:
1. 找到行内最大元,作为主元,看主元是否在对角线上,如果不在,比如在(1,3),那么交换第一行和第三行,让此主元位于(3,3)【矩阵 A,B 要对应同步操作,即B也要1、3行交换】,标记dirty[3]=true,意思是,准备搞第三行。
2. (第一行已经成了第三行) 把(3,3)位置元素化为1, 同时第三行其他元素都同时除以(3,3)的值。矩阵B第三行个元素同时除以 A的(3,3) 的值。
3. (第三行(3,3)已经归一) 用等式三去减其他行,把第一二行的第三列搞成0,因为他们不在对角线。
这是一次循环结束。重复循环n次,直到n个dirty全都true。此时A已经是单位矩阵,矩阵B就是解矩阵
个人疑惑:不知道为什么要选取最大元素作为主元。个人觉得只要是非零元素就可以做主元了。。有人说是稳定性考虑,暂时不明白。存疑
原文链接:http://blog.csdn.net/zhangxaochen/article/details/8020668
{{OVER}}