Gauss-Jordan 消元法 解方程组

原文链接: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}}

 

 

 

你可能感兴趣的:(C++,c,IO,ini,Matrix,initialization)