【數據結構之旅】稀疏矩陣的快速轉置

說明:

    稀疏矩陣的快速轉置算法的核心在於,用一個數組num記錄原來矩陣中的每列非零元個數,用另一個數組cpos來記錄原矩陣每列第一個非零元在新矩陣中的位置,以此來達到快速轉置的目的。

    用這樣的方法,主要是希望,矩陣轉置後,存儲順序依然是按照行來存儲的。




1.實現及代碼註釋

    根據上面的核心提示,可以有如下的代碼,下面的代碼中的註釋已經非常詳細,因此這裏就不把每一部分實現的功能獨立開來了:

#include<stdio.h>
#include<stdlib.h>
#define OVERFLOW -1
#define OK 1
#define ERROR 0
#define TRUE 2
#define FALSE -2

typedef int ElemType;
typedef int Status;

typedef struct{ //非零元三元組類型結構體 
	int i, j;	//非零元的行和列 
	ElemType e;	//非零元的值 
} Triple;		//非零元三元組類型結構體定義關鍵字

typedef struct{		//矩陣類型結構體 
	Triple *data;	//data域,指向非零元三元組的結構體指針 
	int mu, nu, tu;	//矩陣的行數、列數和非零元個數 
} TSMatrix;			//矩陣類型結構體定義關鍵字

 /*
 	0	14	0	0	-5
 	0	-7	0	0	0
 	36	0	0	28	0
 	
 	mu = 3; nu = 5; tu = 5
*/

Status CreateSMatrix(TSMatrix &M){	//創建一個稀疏矩陣 
	M.tu = 5;
	
	M.data = (Triple*)malloc(sizeof(Triple) * (M.tu + 1)); //data域存儲元素的大小比稀疏矩陣的非零元個數大1,是因爲data[0]不使用 
	if(NULL == M.data)
		return OVERFLOW;
	M.data[1].i = 1;
	M.data[1].j = 2;
	M.data[1].e = 14;
	
	M.data[2].i = 1;
	M.data[2].j = 5;
	M.data[2].e = -5;
	
	M.data[3].i = 2;
	M.data[3].j = 2;
	M.data[3].e = -7;
	
	M.data[4].i = 3;
	M.data[4].j = 1;
	M.data[4].e = 36;
	
	M.data[5].i = 3;
	M.data[5].j = 4;
	M.data[5].e = 28;
	
	M.mu = 3;
	M.nu = 5;
	
	return OK;
}

Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T){ //採用順序表存儲表示,求稀疏矩陣M的轉置矩陣T 
	int j, p, q, t;	
	/*j記錄遍歷時的當前列,cops[j],則表示當前列第一個非零元的位置或者該列非零元位置的其它位置(cops[j]++),正式轉置時用; 
	p記錄遍歷時的非零元個數,正式轉置時用; 
	q記錄cops[j],簡化代碼的表示,正式轉置時用 ;
	t用在轉置準備時。 
	*/
	int *num;	//保存每一列的非零元個數 
	int *cpos;	//保存轉置後每列第一個非零元在T中所處的序號
				//cops[j]++則是該列的下一個非零元,如果存在的話 
	
	T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;	//初始化矩陣T 
	
	T.data = (Triple*)malloc(sizeof(Triple)*(T.nu + 1));
	
	num = (int*)malloc((M.nu + 1)*sizeof(int));	//num和cpos開闢空間比非零元個數大1,是因爲不使用0號位置 
	cpos = (int*)malloc((M.nu + 1)*sizeof(int));
	
	if(num == NULL || cpos == NULL)
		return OVERFLOW;
	
	if(T.tu != 0){
		for(j = 1; j <= M.nu; j++)	//初始化num向量 
			num[j] = 0;
		for(t = 1;t <= M.tu; t++)	//求M中每一列所含非零元的個數 
			num[M.data[t].j]++;		//這裏要用到num[1]~num[5],所以上面num要全部初始化爲0 
		
		cpos[1] = 1;	//這裏是一定的 
		for(j = 2;j <= M.nu; j++)	//求每列的第一個非零元在T.data中的序號  
			cpos[j] = cpos[j-1] + num[j-1];	//畫表分析得出該公式並不難 
		
		for(p = 1; p <= M.tu; p++){		//上面是準備工作,下面開始正式轉置 
			j = M.data[p].j;	//j的作用是記錄當前遍歷的列,以讓cops使用 
			q = cpos[j];		//是爲了簡化代碼,因爲下面都要用到cpos[j] 
			T.data[q].i = M.data[p].j;	//交換行 
			T.data[q].j = M.data[p].i;	//交換列 
			T.data[q].e = M.data[p].e;	//賦值 ,無論如何交換,儲存順序是已經定下來的了 
										
			cpos[j]++;	//cops[j]++則是該列的下一個非零元,如果存在的話,不存在的話也沒有影響 
		}				//因爲在這個for循環中,如果列變了,即j變化了,cpos[j]也不是原來的值了 
	} 
	free(num);
	free(cpos);
	return OK;
}

int main(void){
	int i,j;
	
	TSMatrix M;
	TSMatrix T;
	CreateSMatrix(M);	
	FastTransposeSMatrix(M, T);
	
	printf("\n");
	return 0;
}

    可以用C free等編譯器進行編譯運行,但由於時間關係,上面的代碼中並沒有給出轉置後的矩陣打印的代碼,可以自己加上去,當然也可以通過調試的方法監視新矩陣T中的data域的數值變化。




2.測試

    測試就是按照上面的提示去做就可以了,時間關係,這裏就先不做測試,改天有時間再補上吧。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章