矩陣的壓縮存儲(稀疏矩陣的十字鏈表存儲、稀疏矩陣的三元組行邏輯鏈接的順序表存儲表示、稀疏矩陣的三元組順序表存儲表示)

// c5-2.h 稀疏矩陣的三元組順序表存儲表示(見圖5.4)
#define MAX_SIZE 100 // 非零元個數的最大值
struct Triple
{
	int i,j; // 行下標,列下標
	ElemType e; // 非零元素值
};
struct TSMatrix
{
	Triple data[MAX_SIZE+1]; // 非零元三元組表,data[0]未用
	int mu,nu,tu; // 矩陣的行數、列數和非零元個數
};

圖55 是採用三元組順序表存儲稀疏矩陣的例子。爲簡化算法,在創建稀疏矩陣輸
入非零元時,要按行、列的順序由小到大輸入。

// bo5-2.cpp 三元組稀疏矩陣的基本操作(8個),包括算法5.1
Status CreateSMatrix(TSMatrix &M)
{ // 創建稀疏矩陣M
	int i,m,n;
	ElemType e;
	Status k;
	printf("請輸入矩陣的行數,列數,非零元素數:");
	scanf("%d,%d,%d",&M.mu,&M.nu,&M.tu);
	if(M.tu>MAX_SIZE)
		return ERROR;
	M.data[0].i=0; // 爲以下比較順序做準備
	for(i=1;i<=M.tu;i++)
	{
		do
		{
			printf("請按行序順序輸入第%d個非零元素所在的行(1~%d),列(1~%d),元素值:",i,M.mu,M.nu);
			scanf("%d,%d,%d",&m,&n,&e);
			k=0;
			if(m<1||m>M.mu||n<1||n>M.nu) // 行或列超出範圍
				k=1;
			if(m<M.data[i-1].i||m==M.data[i-1].i&&n<=M.data[i-1].j) // 行或列的順序有錯
				k=1;
		}while(k);
		M.data[i].i=m;
		M.data[i].j=n;
		M.data[i].e=e;
	}
	return OK;
}
void DestroySMatrix(TSMatrix &M)
{ // 銷燬稀疏矩陣M(見圖5.6)
	M.mu=M.nu=M.tu=0;
}
void PrintSMatrix(TSMatrix M)
{ // 輸出稀疏矩陣M
	int i;
	printf("%d行%d列%d個非零元素。\n",M.mu,M.nu,M.tu);
	printf("行列元素值\n");
	for(i=1;i<=M.tu;i++)
		printf("%2d%4d%8d\n",M.data[i].i,M.data[i].j,M.data[i].e);
}
void PrintSMatrix1(TSMatrix M)
{ // 按矩陣形式輸出M
	int i,j,k=1;
	Triple *p=M.data;
	p++; // p指向第1個非零元素
	for(i=1;i<=M.mu;i++)
	{
		for(j=1;j<=M.nu;j++)
			if(k<=M.tu&&p->i==i&&p->j==j) // p指向非零元,且p所指元素爲當前處理元素
			{
				printf("%3d",p->e); // 輸出p所指元素的值
				p++; // p指向下一個元素
				k++; // 計數器+1
			}
			else // p所指元素不是當前處理元素
				printf("%3d",0); // 輸出0
			printf("\n");
	}
}
void CopySMatrix(TSMatrix M,TSMatrix &T)
{ // 由稀疏矩陣M複製得到T
	T=M;
}
int comp(int c1,int c2)
{ // AddSMatrix函數要用到,另加
	if(c1<c2)
		return -1;
	if(c1==c2)
		return 0;
	return 1;
}
Status AddSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{ // 求稀疏矩陣的和Q=M+N
	int m=1,n=1,q=0;
	if(M.mu!=N.mu||M.nu!=N.nu) // M、N兩稀疏矩陣行或列數不同
		return ERROR;
	Q.mu=M.mu;
	Q.nu=M.nu;
	while(m<=M.tu&&n<=N.tu) // 矩陣M和N的元素都沒處理完
	{
		switch(comp(M.data[m].i,N.data[n].i))
		{
		case -1: Q.data[++q]=M.data[m++]; // 將矩陣M的當前元素值賦給矩陣Q
			break;
		case 0: switch(comp(M.data[m].j,N.data[n].j)) // M、N矩陣當前元素的行相等,繼續比較列
				{
		case -1: Q.data[++q]=M.data[m++];
			break;
		case 0: Q.data[++q]=M.data[m++]; // M、N矩陣當前非零元素的行列均相等
			Q.data[q].e+=N.data[n++].e; //矩陣M、N的當前元素值求和並賦給矩陣Q
			if(Q.data[q].e==0) // 元素值爲0,不存入壓縮矩陣
				q--;
			break;
		case 1: Q.data[++q]=N.data[n++];
				}
			break;
		case 1: Q.data[++q]=N.data[n++]; // 將矩陣N的當前元素值賦給矩陣Q
		}
	}
	while(m<=M.tu) // 矩陣N的元素全部處理完畢
		Q.data[++q]=M.data[m++];
	while(n<=N.tu) // 矩陣M的元素全部處理完畢
		Q.data[++q]=N.data[n++];
	Q.tu=q; // 矩陣Q的非零元素個數
	if(q>MAX_SIZE) // 非零元素個數太多
		return ERROR;
	return OK;
}
Status SubtSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{ // 求稀疏矩陣的差Q=M-N
	int i;
	for(i=1;i<=N.tu;i++)
		N.data[i].e*=-1;
	return AddSMatrix(M,N,Q);
}
void TransposeSMatrix(TSMatrix M,TSMatrix &T)
{ // 求稀疏矩陣M的轉置矩陣T。算法5.1改
	int p,q,col;
	T.mu=M.nu;
	T.nu=M.mu;
	T.tu=M.tu;
	if(T.tu)
	{
		q=1;
		for(col=1;col<=M.nu;++col)
			for(p=1;p<=M.tu;++p)
				if(M.data[p].j==col)
				{
					T.data[q].i=M.data[p].j;
					T.data[q].j=M.data[p].i;
					T.data[q].e=M.data[p].e;
					++q;
				}
	}
}
Status MultSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{ // 求稀疏矩陣的乘積Q=M×N
	int i,j;
	ElemType *Nc,*Tc;
	TSMatrix T; // 臨時矩陣
	if(M.nu!=N.mu)
		return ERROR;
	T.nu=M.mu; // 臨時矩陣T是Q的轉秩矩陣
	T.mu=N.nu;
	T.tu=0;
	Nc=(ElemType*)malloc((N.mu+1)*sizeof(ElemType));//Nc爲矩陣N一列的臨時數組(非壓縮,[0]不用)
	Tc=(ElemType*)malloc((M.nu+1)*sizeof(ElemType));//Tc爲矩陣T一行的臨時數組(非壓縮,[0]不用)
	if(!Nc||!Tc) // 創建臨時數組不成功
		exit(ERROR);
	for(i=1;i<=N.nu;i++) // 對於N的每一列
	{
		for(j=1;j<=N.mu;j++)
			Nc[j]=0; // 矩陣Nc的初值爲0
		for(j=1;j<=M.mu;j++)
			Tc[j]=0; // 臨時數組Tc的初值爲0,[0]不用
		for(j=1;j<=N.tu;j++) // 對於N的每一個非零元素
			if(N.data[j].j==i) // 屬於第i列
				Nc[N.data[j].i]=N.data[j].e; // 根據其所在行將其元素值賦給相應的Nc
			for(j=1;j<=M.tu;j++) // 對於M的每一個值
				Tc[M.data[j].i]+=M.data[j].e*Nc[M.data[j].j]; // Tc中存N的第i列與M相乘的結果
			for(j=1;j<=M.mu;j++)
				if(Tc[j]!=0)
				{
					T.data[++T.tu].e=Tc[j];
					T.data[T.tu].i=i;
					T.data[T.tu].j=j;
				}
	}
	if(T.tu>MAX_SIZE) // 非零元素個數太多
		return ERROR;
	TransposeSMatrix(T,Q); // 將T的轉秩賦給Q
	DestroySMatrix(T); // 銷燬臨時矩陣T
	free(Tc); // 釋放動態數組Tc和Nc
	free(Nc);
	return OK;
}


// main5-2.cpp 檢驗bo5-2.cpp的主程序
#include"c1.h"
typedef int ElemType;
#include"c5-2.h"
#include"bo5-2.cpp"
void main()
{
	TSMatrix A,B,C;
	printf("創建矩陣A: ");
	CreateSMatrix(A);
	PrintSMatrix(A);
	printf("由矩陣A複製矩陣B:\n");
	CopySMatrix(A,B);
	PrintSMatrix1(B);
	DestroySMatrix(B);
	printf("銷燬矩陣B後:\n");
	PrintSMatrix1(B);
	printf("創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲%d,%d)\n",A.mu,A.nu);
	CreateSMatrix(B);
	PrintSMatrix1(B);
	AddSMatrix(A,B,C);
	printf("矩陣C1(A+B):\n");
	PrintSMatrix1(C);
	SubtSMatrix(A,B,C);
	printf("矩陣C2(A-B):\n");
	PrintSMatrix1(C);
	TransposeSMatrix(A,C);
	printf("矩陣C3(A的轉置):\n");
	PrintSMatrix1(C);
	printf("創建矩陣A2: ");
	CreateSMatrix(A);
	PrintSMatrix1(A);
	printf("創建矩陣B3:(行數應與矩陣A2的列數相同=%d)\n",A.nu);
	CreateSMatrix(B);
	PrintSMatrix1(B);
	MultSMatrix(A,B,C);
	printf("矩陣C5(A×B):\n");
	PrintSMatrix1(C);
}

代碼的運行結果:

創建矩陣A: 請輸入矩陣的行數,列數,非零元素數:3,3,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~3),元素值:2,2,2
3行3列2個非零元素。(見圖57)
行列元素值
1 2 1
2 2 2
由矩陣A複製矩陣B:
0 1 0
0 2 0
0 0 0
銷燬矩陣B後:
創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲3,3)
請輸入矩陣的行數,列數,非零元素數:3,3,1
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
0 1 0
0 0 0
0 0 0
矩陣C1(A+B):
0 2 0
0 2 0
0 0 0
矩陣C2(A-B):
0 0 0
0 2 0
0 0 0
矩陣C3(A的轉置):
0 0 0
1 2 0

0 0 0
創建矩陣A2: 請輸入矩陣的行數,列數,非零元素數:2,3,2
請按行序順序輸入第1個非零元素所在的行(1~2),列(1~3),元素值:1,1,1
請按行序順序輸入第2個非零元素所在的行(1~2),列(1~3),元素值:2,3,2
1 0 0
0 0 2
創建矩陣B3:(行數應與矩陣A2的列數相同=3)
請輸入矩陣的行數,列數,非零元素數:3,2,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~2),元素值:2,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~2),元素值:3,1,2
0 0
0 1
2 0
矩陣C5(A×B):
0 0
4 0


// algo5-1.cpp 實現算法5.2的程序
#include"c1.h"
typedef int ElemType;
#include"c5-2.h"
#include"bo5-2.cpp"
void FastTransposeSMatrix(TSMatrix M,TSMatrix &T)
{ // 快速求稀疏矩陣M的轉置矩陣T。算法5.2改
	int p,q,t,col,*num,*cpot;
	num=(int *)malloc((M.nu+1)*sizeof(int)); // 存M每列(T每行)非零元素個數([0]不用)
	cpot=(int *)malloc((M.nu+1)*sizeof(int)); // 存T每行的下1個非零元素的存儲位置([0]不用)
	T.mu=M.nu; // 給T的行、列數與非零元素個數賦值
	T.nu=M.mu;
	T.tu=M.tu;
	if(T.tu) // 是非零矩陣
	{
		for(col=1;col<=M.nu;++col)
			num[col]=0; // 計數器初值設爲0
		for(t=1;t<=M.tu;++t) // 求M中每一列含非零元素個數
			++num[M.data[t].j];
		cpot[1]=1; // T的第1行的第1個非零元在T.data中的序號爲1
		for(col=2;col<=M.nu;++col)
			cpot[col]=cpot[col-1]+num[col-1]; // 求T的第col行的第1個非零元在T.data中的序號
		for(p=1;p<=M.tu;++p) // 從M的第1個元素開始
		{
			col=M.data[p].j; // 求得在M中的列數
			q=cpot[col]; // q指示M當前的元素在T中的序號
			T.data[q].i=M.data[p].j;
			T.data[q].j=M.data[p].i;
			T.data[q].e=M.data[p].e;
			++cpot[col]; // T第col行的下1個非零元在T.data中的序號
		}
	}
	free(num);
	free(cpot);
}
void main()
{
	TSMatrix A,B;
	printf("創建矩陣A: ");
	CreateSMatrix(A);
	PrintSMatrix1(A);
	FastTransposeSMatrix(A,B);
	printf("矩陣B(A的快速轉置):\n");
	PrintSMatrix1(B);
}

代碼的運行結果:

創建矩陣A: 請輸入矩陣的行數,列數,非零元素數:3,2,4
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~2),元素值:1,1,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~2),元素值:2,1,2
請按行序順序輸入第3個非零元素所在的行(1~3),列(1~2),元素值:3,1,3
請按行序順序輸入第4個非零元素所在的行(1~3),列(1~2),元素值:3,2,4
1 0
2 0
3 4
矩陣B(A的快速轉置):
1 2 3
0 0 4

由於稀疏矩陣的三元組順序表存儲結構要求先按行、同行再按列順序存儲非零元素,
算法5.1(在bo5-2.cpp 中)採用了雙重循環求轉置矩陣,對於外層循環col(列)的每一個
值,對所有的非零元素,如果其列數與col 相等,則按順序存入轉秩矩陣。這就保證了轉
秩矩陣也是先按行、同行再按列順序存儲非零元素。所以它的時間複雜度爲O(列數×非
零元素數)。而算法5.2(在algo5-1.cpp 中)採用了2 個單循環。第1 個循環,對所有的非
零元素,計算其所在列並計數,得到每列的非零元素數num[col]及每列第1 個非零元素在
轉秩矩陣中的存儲位置cpot[col]。第2 個循環,對所有的非零元素,根據其列數和
cpot[col]的當前值,存入轉秩矩陣。由於還要給num[col]和cpot[col]賦初值,它的時間復
雜度爲O(列數+非零元素數)。

// c5-3.h 稀疏矩陣的三元組行邏輯鏈接的順序表存儲表示(見圖5.8)
#define MAX_SIZE 100 // 非零元個數的最大值
#define MAX_RC 20 // 最大行列數
struct Triple // 同c5-2.h
{
	int i,j; // 行下標,列下標
	ElemType e; // 非零元素值
};
struct RLSMatrix
{
	Triple data[MAX_SIZE+1]; // 非零元三元組表,data[0]未用
	int rpos[MAX_RC+1]; // 各行第一個非零元素的位置表,比c5-2.h增加的項
	int mu,nu,tu; // 矩陣的行數、列數和非零元個數
};


三元組行邏輯鏈接的順序表存儲表示(c5-3.h)比三元組順序表存儲表示(c5-2.h)增加
了rpos 數組,用以存放各行的第一個非零元素在data 數組中的位置。這樣,就可以迅速地
找到某一行的元素。圖59 是採用三元組行邏輯鏈接的順序表存儲稀疏矩陣的實例。和
c5-2.h 存儲結構一樣,創建稀疏矩陣輸入非零元時,也要按行、列的順序由小到大輸入。

// bo5-3.cpp 行邏輯鏈接稀疏矩陣(存儲結構由c5-3.h定義)的基本操作(8個),包括算法5.3
Status CreateSMatrix(RLSMatrix &M)
{ // 創建稀疏矩陣M
	int i,j;
	Triple T;
	Status k;
	printf("請輸入矩陣的行數,列數,非零元素數:");
	scanf("%d,%d,%d",&M.mu,&M.nu,&M.tu);
	if(M.tu>MAX_SIZE||M.mu>MAX_RC)
		return ERROR;
	M.data[0].i=0; // 爲以下比較做準備
	for(i=1;i<=M.tu;i++)
	{
		do
		{
			printf("請按行序順序輸入第%d個非零元素所在的行(1~%d),列(1~%d),元素值:",i,M.mu,M.nu);
			scanf("%d,%d,%d",&T.i,&T.j,&T.e);
			k=0;
			if(T.i<1||T.i>M.mu||T.j<1||T.j>M.nu) // 行、列超出範圍
				k=1;
			if(T.i<M.data[i-1].i||T.i==M.data[i-1].i&&T.j<=M.data[i-1].j)//沒有按順序輸入非零元素
				k=1;
		}while(k); // 當輸入有誤,重新輸入
		M.data[i]=T;
	}
	for(i=1;i<=M.mu;i++) // 給rpos[]賦初值0
		M.rpos[i]=0;
	for(i=1;i<=M.tu;i++) // 計算每行非零元素數並賦給rpos[]
		M.rpos[M.data[i].i]++;
	for(i=M.mu;i>=1;i--) // 計算rpos[]
	{
		M.rpos[i]=1; // 賦初值1
		for(j=i-1;j>=1;j--)
			M.rpos[i]+=M.rpos[j];
	}
	return OK;
}
void DestroySMatrix(RLSMatrix &M)
{ // 銷燬稀疏矩陣M(使M爲0行0列0個非零元素的矩陣)
	M.mu=M.nu=M.tu=0;
}
void PrintSMatrix(RLSMatrix M)
{ // 輸出稀疏矩陣M
	int i;
	printf("%d行%d列%d個非零元素。\n",M.mu,M.nu,M.tu);
	printf("行列元素值\n");
	for(i=1;i<=M.tu;i++)
		printf("%2d%4d%8d\n",M.data[i].i,M.data[i].j,M.data[i].e);
	for(i=1;i<=M.mu;i++)
		printf("第%d行的第一個非零元素是本矩陣第%d個元素\n",i,M.rpos[i]);
}
void PrintSMatrix1(RLSMatrix M)
{ // 按矩陣形式輸出M
	int i,j,k=1;
	Triple *p=M.data;
	p++; // p指向第1個非零元素
	for(i=1;i<=M.mu;i++)
	{
		for(j=1;j<=M.nu;j++)
			if(k<=M.tu&&p->i==i&&p->j==j) // p指向非零元,且p所指元素爲當前處理元素
			{
				printf("%3d",p->e); // 輸出p所指元素的值
				p++; // p指向下一個元素
				k++; // 計數器+1
			}
			else // p所指元素不是當前處理元素
				printf("%3d",0); // 輸出0
			printf("\n");
	}
}
void CopySMatrix(RLSMatrix M,RLSMatrix &T)
{ // 由稀疏矩陣M複製得到T
	T=M;
}
Status AddSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩陣的和Q=M+N
	int k,p,q,tm,tn;
	if(M.mu!=N.mu||M.nu!=N.nu)
		return ERROR;
	Q.mu=M.mu; // Q矩陣行數
	Q.nu=M.nu; // Q矩陣列數
	Q.tu=0; // Q矩陣非零元素數初值
	for(k=1;k<=M.mu;++k) // 對於每一行,k指示行號
	{
		Q.rpos[k]=Q.tu+1; // Q矩陣第k行的第1個元素的位置
		p=M.rpos[k]; // p指示M矩陣第k行當前元素的序號
		q=N.rpos[k]; // q指示N矩陣第k行當前元素的序號
		if(k==M.mu) // 是最後一行
		{
			tm=M.tu+1; // tm,tn分別是p,q的上界
			tn=N.tu+1;
		}
		else
		{
			tm=M.rpos[k+1];
			tn=N.rpos[k+1];
		}
		while(p<tm&&q<tn) // M,N矩陣均有第k行元素未處理
			if(M.data[p].j==N.data[q].j) // M矩陣當前元素的列=N矩陣當前元素的列
			{
				if(M.data[p].e+N.data[q].e!=0) // 和不爲0,存入Q
				{
					Q.data[++Q.tu]=M.data[p];
					Q.data[Q.tu].e+=N.data[q].e;
				}
				p++;
				q++;
			}
			else if(M.data[p].j<N.data[q].j) // M矩陣當前元素的列<N矩陣當前元素的列
				Q.data[++Q.tu]=M.data[p++]; // 將M的當前值賦給Q
			else // M矩陣當前元素的列>N矩陣當前元素的列
				Q.data[++Q.tu]=N.data[q++]; // 將N的當前值賦給Q
			while(p<tm) // M矩陣還有第k行的元素未處理
				Q.data[++Q.tu]=M.data[p++]; // 將M的當前值賦給Q
			while(q<tn) // N矩陣還有k行的元素未處理
				Q.data[++Q.tu]=N.data[q++]; // 將N的當前值賦給Q
	}
	if(Q.tu>MAX_SIZE)
		return ERROR;
	else
		return OK;
}
Status SubtSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩陣的差Q=M-N
	int i;
	if(M.mu!=N.mu||M.nu!=N.nu)
		return ERROR;
	for(i=1;i<=N.tu;++i) // 對於N的每一元素,其值乘以-1
		N.data[i].e*=-1;
	AddSMatrix(M,N,Q); // Q=M+(-N)
	return OK;
}
Status MultSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩陣乘積Q=M×N。算法5.3改
	int arow,brow,p,q,ccol,ctemp[MAX_RC+1],t,tp;
	if(M.nu!=N.mu) // 矩陣M的列數應和矩陣N的行數相等
		return ERROR;
	Q.mu=M.mu; // Q初始化
	Q.nu=N.nu;
	Q.tu=0;
	if(M.tu*N.tu==0) // M和N至少有一個是零矩陣
		return ERROR;
	for(arow=1;arow<=M.mu;++arow)
	{ // 從M的第一行開始,到最後一行,arow是M的當前行
		for(ccol=1;ccol<=Q.nu;++ccol)
			ctemp[ccol]=0; // Q的當前行的各列元素累加器清零
		Q.rpos[arow]=Q.tu+1; // Q當前行的第1個元素位於上1行最後1個元素之後
		if(arow<M.mu)
			tp=M.rpos[arow+1];
		else
			tp=M.tu+1; // 給最後1行設界
		for(p=M.rpos[arow];p<tp;++p)
		{ // 對M當前行中每一個非零元
			brow=M.data[p].j; // 找到對應元在N中的行號(M當前元的列號)
			if(brow<N.mu)
				t=N.rpos[brow+1];
			else
				t=N.tu+1; // 給最後1行設界
			for(q=N.rpos[brow];q<t;++q)
			{
				ccol=N.data[q].j; // 乘積元素在Q中列號
				ctemp[ccol]+=M.data[p].e*N.data[q].e;
			}
		} // 求得Q中第arow行的非零元
		for(ccol=1;ccol<=Q.nu;++ccol) // 壓縮存儲該行非零元
			if(ctemp[ccol]!=0)
			{
				if(++Q.tu>MAX_SIZE)
					return ERROR;
				Q.data[Q.tu].i=arow;
				Q.data[Q.tu].j=ccol;
				Q.data[Q.tu].e=ctemp[ccol];
			}
	}
	return OK;
}
void TransposeSMatrix(RLSMatrix M,RLSMatrix &T)
{ // 求稀疏矩陣M的轉置矩陣T
	int p,q,t,col,*num;
	num=(int *)malloc((M.nu+1)*sizeof(int));
	T.mu=M.nu;
	T.nu=M.mu;
	T.tu=M.tu;
	if(T.tu)
	{
		for(col=1;col<=M.nu;++col)
			num[col]=0; // 設初值
		for(t=1;t<=M.tu;++t) // 求M中每一列非零元個數
			++num[M.data[t].j];
		T.rpos[1]=1;
		for(col=2;col<=M.nu;++col) // 求M中第col中第一個非零元在T.data中的序號
			T.rpos[col]=T.rpos[col-1]+num[col-1];
		for(col=1;col<=M.nu;++col)
			num[col]=T.rpos[col];
		for(p=1;p<=M.tu;++p)
		{
			col=M.data[p].j;
			q=num[col];
			T.data[q].i=M.data[p].j;
			T.data[q].j=M.data[p].i;
			T.data[q].e=M.data[p].e;
			++num[col];
		}
	}
	free(num);
}

// main5-3.cpp 檢驗bo5-3.cpp的主程序(與main5-2.cpp很相像)
#include"c1.h"
typedef int ElemType;
#include"c5-3.h" // 此行與main5-2.cpp不同
#include"bo5-3.cpp" // 此行與main5-2.cpp不同
void main()
{
	RLSMatrix A,B,C; // 此行與main5-2.cpp不同
	printf("創建矩陣A: ");
	CreateSMatrix(A);
	PrintSMatrix(A);
	printf("由矩陣A複製矩陣B:\n");
	CopySMatrix(A,B);
	PrintSMatrix1(B);
	DestroySMatrix(B);
	printf("銷燬矩陣B後:\n");
	PrintSMatrix1(B);
	printf("創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲%d,%d)\n",A.mu,A.nu);
	CreateSMatrix(B);
	PrintSMatrix1(B);
	AddSMatrix(A,B,C);
	printf("矩陣C1(A+B):\n");
	PrintSMatrix1(C);
	SubtSMatrix(A,B,C);
	printf("矩陣C2(A-B):\n");
	PrintSMatrix1(C);
	TransposeSMatrix(A,C);
	printf("矩陣C3(A的轉置):\n");
	PrintSMatrix1(C);
	printf("創建矩陣A2:\n");
	CreateSMatrix(A);
	PrintSMatrix1(A);
	printf("創建矩陣B3:(行數應與矩陣A2的列數相同=%d)\n",A.nu);
	CreateSMatrix(B);
	PrintSMatrix1(B);
	MultSMatrix(A,B,C);
	printf("矩陣C5(A×B):\n");
	PrintSMatrix1(C);
}

代碼的運行結果:

創建矩陣A: 請輸入矩陣的行數,列數,非零元素數:3,3,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~3),元素值:2,2,2
3行3列2個非零元素。(見圖57)
行列元素值
1 2 1
2 2 2
第1行的第一個非零元素是本矩陣第1個元素
第2行的第一個非零元素是本矩陣第2個元素
第3行的第一個非零元素是本矩陣第3個元素
由矩陣A複製矩陣B:
0 1 0
0 2 0
0 0 0
銷燬矩陣B後:
創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲3,3)
請輸入矩陣的行數,列數,非零元素數:3,3,1
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
0 1 0
0 0 0

0 0 0
矩陣C1(A+B):
0 2 0
0 2 0
0 0 0
矩陣C2(A-B):
0 0 0
0 2 0
0 0 0
矩陣C3(A的轉置):
0 0 0
1 2 0
0 0 0
創建矩陣A2:
請輸入矩陣的行數,列數,非零元素數:2,3,2
請按行序順序輸入第1個非零元素所在的行(1~2),列(1~3),元素值:1,1,1
請按行序順序輸入第2個非零元素所在的行(1~2),列(1~3),元素值:2,3,2
1 0 0
0 0 2
創建矩陣B3:(行數應與矩陣A2的列數相同=3)
請輸入矩陣的行數,列數,非零元素數:3,2,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~2),元素值:2,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~2),元素值:3,1,2
0 0
0 1
2 0
矩陣C5(A×B):
0 0
4 0

// c5-4.h 稀疏矩陣的十字鏈表存儲表示(見圖5.10)
struct OLNode
{
	int i,j; // 該非零元的行和列下標
	ElemType e; // 非零元素值
	OLNode *right,*down;
	// 該非零元所在行表和列表的後繼鏈域
};
typedef OLNode *OLink;
struct CrossList
{
	OLink *rhead,*chead;
	// 行和列鏈表頭指針向量基址,由CreatSMatrix_OL()分配
	int mu,nu,tu; // 稀疏矩陣的行數、列數和非零元個數
};



圖511 是採用十字鏈表存儲稀疏矩陣的實例(教科書圖5.6)。由於十字鏈表存儲結
構中的非零元素是按其所在行、列插入相應的鏈表的,所以,在創建稀疏矩陣輸入非零元
時,可以按任意順序輸入非零元素。每個非零元結點按升序被插入到兩個沒有頭結點的單
鏈表中:一個是所在行鏈表;另一個是所在列鏈表。當插入或刪除結點時,只要修改相關的行、列鏈表即可,比較靈活。


// bo5-4.cpp 稀疏矩陣的十字鏈表存儲(存儲結構由c5-4.h定義)的基本操作(9個),包括算法5.4
void InitSMatrix(CrossList &M)
{ // 初始化M(CrossList類型的變量必須初始化,否則創建、複製矩陣將出錯)。加(見圖5.12)
	M.rhead=M.chead=NULL;
	M.mu=M.nu=M.tu=0;
}
void InitSMatrixList(CrossList &M)
{ // 初始化十字鏈表表頭指針向量。加(見圖5.13)
	int i;
	if(!(M.rhead=(OLink*)malloc((M.mu+1)*sizeof(OLink))))
		// 生成行表頭指針向量
		exit(OVERFLOW);
	if(!(M.chead=(OLink*)malloc((M.nu+1)*sizeof(OLink))))
		// 生成列表頭指針向量
		exit(OVERFLOW);
	for(i=1;i<=M.mu;i++)
		// 初始化矩陣T的行表頭指針向量,各行鏈表爲空
		M.rhead[i]=NULL;
	for(i=1;i<=M.nu;i++)
		// 初始化矩陣T的列表頭指針向量,各列鏈表爲空
		M.chead[i]=NULL;
}
void InsertAscend(CrossList &M,OLink p)
{ // 初始條件:稀疏矩陣M存在,p指向的結點存在。
	// 操作結果:按行列升序將p所指結點插入M(見圖5.14)
	OLink q=M.rhead[p->i]; // q指向待插行表
	if(!q||p->j<q->j) // 待插的行表空或p所指結點的列值小於首結點的列值
	{
		p->right=M.rhead[p->i]; // 插在表頭
		M.rhead[p->i]=p;
	}
	else
	{
		while(q->right&&q->right->j<p->j)//q所指不是尾結點且q的下一結點的列值小於p所指結點的列值
			q=q->right; // q向後移
		p->right=q->right; // 將p插在q所指結點之後
		q->right=p;
	}
	q=M.chead[p->j]; // q指向待插列表
	if(!q||p->i<q->i) // 待插的列表空或p所指結點的行值小於首結點的行值
	{
		p->down=M.chead[p->j]; // 插在表頭
		M.chead[p->j]=p;
	}
	else
	{
		while(q->down&&q->down->i<p->i) //q所指不是尾結點且q的下一結點的行值小於p所指結點的行值
			q=q->down; // q向下移
		p->down=q->down; // 將p插在q所指結點之下
		q->down=p;
	}
	M.tu++;
}
void DestroySMatrix(CrossList &M)
{ // 初始條件:稀疏矩陣M存在。操作結果:銷燬稀疏矩陣M(見圖5.12)
	int i;
	OLink p,q;
	for(i=1;i<=M.mu;i++) // 按行釋放結點
	{
		p=*(M.rhead+i);
		while(p)
		{
			q=p;
			p=p->right;
			free(q);
		}
	}
	free(M.rhead);
	free(M.chead);
	InitSMatrix(M);
}
void CreateSMatrix(CrossList &M)
{ // 創建稀疏矩陣M,採用十字鏈表存儲表示。算法5.4改
	int i,k;
	OLink p;
	if(M.rhead)
		DestroySMatrix(M);
	printf("請輸入稀疏矩陣的行數列數非零元個數: ");
	scanf("%d%d%d",&M.mu,&M.nu,&i);
	InitSMatrixList(M); // 初始化M的表頭指針向量
	printf("請按任意次序輸入%d個非零元的行列元素值:\n",M.tu);
	for(k=0;k<i;k++)
	{
		p=(OLink)malloc(sizeof(OLNode)); // 生成結點
		if(!p)
			exit(OVERFLOW);
		scanf("%d%d%d",&p->i,&p->j,&p->e); // 給結點的3個成員賦值
		InsertAscend(M,p); // 將結點p按行列值升序插到矩陣M中
	}
}
void PrintSMatrix(CrossList M)
{ // 初始條件:稀疏矩陣M存在。操作結果:按行或按列輸出稀疏矩陣M
	int i,j;
	OLink p;
	printf("%d行%d列%d個非零元素\n",M.mu,M.nu,M.tu);
	printf("請輸入選擇(1.按行輸出2.按列輸出): ");
	scanf("%d",&i);
	switch(i)
	{
	case 1: for(j=1;j<=M.mu;j++)
			{
				p=M.rhead[j];
				while(p)
				{
					cout<<p->i<<"行"<<p->j<<"列值爲"<<p->e<<endl;
					p=p->right;
				}
			}
		break;
	case 2: for(j=1;j<=M.nu;j++)
			{
				p=M.chead[j];
				while(p)
				{
					cout<<p->i<<"行"<<p->j<<"列值爲"<<p->e<<endl;
					p=p->down;
				}
			}
	}
}
void PrintSMatrix1(CrossList M)
{ // 按矩陣形式輸出M
	int i,j;
	OLink p;
	for(i=1;i<=M.mu;i++)
	{ // 從第1行到最後1行
		p=M.rhead[i]; // p指向該行的第1個非零元素
		for(j=1;j<=M.nu;j++) // 從第1列到最後1列
			if(!p||p->j!=j) // 已到該行表尾或當前結點的列值不等於當前列值
				printf("%-3d",0); // 輸出0
			else
			{
				printf("%-3d",p->e);
				p=p->right;
			}
			printf("\n");
	}
}
void CopySMatrix(CrossList M,CrossList &T)
{ // 初始條件:稀疏矩陣M存在。操作結果:由稀疏矩陣M複製得到T
	int i;
	OLink p,q;
	if(T.rhead) // 矩陣T存在
		DestroySMatrix(T);
	T.mu=M.mu;
	T.nu=M.nu;
	InitSMatrixList(T); // 初始化T的表頭指針向量
	for(i=1;i<=M.mu;i++) // 按行復制
	{
		p=M.rhead[i]; // p指向i行鏈表頭
		while(p) // 沒到行尾
		{
			if(!(q=(OLNode*)malloc(sizeof(OLNode)))) // 生成結點q
				exit(OVERFLOW);
			*q=*p; // 給結點q賦值
			InsertAscend(T,q); // 將結點q按行列值升序插到矩陣T中
			p=p->right;
		}
	}
}
int comp(int c1,int c2)
{ // AddSMatrix函數要用到,另加
	if(c1<c2)
		return -1;
	if(c1==c2)
		return 0;
	return 1;
}
void AddSMatrix(CrossList M,CrossList N,CrossList &Q)
{ // 初始條件:稀疏矩陣M與N的行數和列數對應相等。操作結果:求稀疏矩陣的和Q=M+N
	int i;
	OLink pq,pm,pn;
	if(M.mu!=N.mu||M.nu!=N.nu)
	{
		printf("兩個矩陣不是同類型的,不能相加\n");
		exit(OVERFLOW);
	}
	Q.mu=M.mu; // 初始化Q矩陣
	Q.nu=M.nu;
	Q.tu=0; // Q矩陣元素個數的初值爲0
	InitSMatrixList(Q); // 初始化Q的表頭指針向量
	for(i=1;i<=M.mu;i++) // 按行的順序相加
	{
		pm=M.rhead[i]; // pm指向矩陣M的第i行的第1個結點
		pn=N.rhead[i]; // pn指向矩陣N的第i行的第1個結點
		while(pm&&pn) // pm和pn均不空
		{
			pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
			switch(comp(pm->j,pn->j))
			{
			case -1: *pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
				InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
				pm=pm->right; // 指針向後移
				break;
			case 0: *pq=*pm; // M、N矩陣的列相等,元素值相加
				pq->e+=pn->e;
				if(pq->e!=0) // 和爲非零元素
					InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
				else
					free(pq); // 釋放結點
				pm=pm->right; // 指針向後移
				pn=pn->right;
				break;
			case 1: *pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
				InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
				pn=pn->right; // 指針向後移
			}
		}
		while(pm) // pn=NULL
		{
			pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
			*pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
			InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
			pm=pm->right; // 指針向後移
		}
		while(pn) // pm=NULL
		{
			pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
			*pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
			InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
			pn=pn->right; // 指針向後移
		}
	}
	if(Q.tu==0) // Q矩陣元素個數爲0
		DestroySMatrix(Q); // 銷燬矩陣Q
}
void SubtSMatrix(CrossList M,CrossList N,CrossList &Q)
{ // 初始條件:稀疏矩陣M與N的行數和列數對應相等。操作結果:求稀疏矩陣的差Q=M-N
	int i;
	OLink pq,pm,pn;
	if(M.mu!=N.mu||M.nu!=N.nu)
	{
		printf("兩個矩陣不是同類型的,不能相減\n");
		exit(OVERFLOW);
	}
	Q.mu=M.mu; // 初始化Q矩陣
	Q.nu=M.nu;
	Q.tu=0; // Q矩陣元素個數的初值爲0
	InitSMatrixList(Q); // 初始化Q的表頭指針向量
	for(i=1;i<=M.mu;i++) // 按行的順序相減
	{
		pm=M.rhead[i]; // pm指向矩陣M的第i行的第1個結點
		pn=N.rhead[i]; // pn指向矩陣N的第i行的第1個結點
		while(pm&&pn) // pm和pn均不空
		{
			pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
			switch(comp(pm->j,pn->j))
			{
			case -1: *pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
				InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
				pm=pm->right; // 指針向後移
				break;
			case 0: *pq=*pm; // M、N矩陣的列相等,元素值相減
				pq->e-=pn->e;
				if(pq->e!=0) // 差爲非零元素
					InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
				else
					free(pq); // 釋放結點
				pm=pm->right; // 指針向後移
				pn=pn->right;
				break;
			case 1: *pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
				pq->e*=-1; // 求反
				InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
				pn=pn->right; // 指針向後移
			}
		}
		while(pm) // pn=NULL
		{
			pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
			*pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
			InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
			pm=pm->right; // 指針向後移
		}
		while(pn) // pm=NULL
		{
			pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
			*pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
			pq->e*=-1; // 求反
			InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
			pn=pn->right; // 指針向後移
		}
	}
	if(Q.tu==0) // Q矩陣元素個數爲0
		DestroySMatrix(Q); // 銷燬矩陣Q
}
void MultSMatrix(CrossList M,CrossList N,CrossList &Q)
{ // 初始條件:稀疏矩陣M的列數等於N的行數。操作結果:求稀疏矩陣乘積Q=M×N
	int i,j,e;
	OLink pq,pm,pn;
	InitSMatrix(Q);
	Q.mu=M.mu;
	Q.nu=N.nu;
	Q.tu=0;
	InitSMatrixList(Q); // 初始化Q的表頭指針向量
	for(i=1;i<=Q.mu;i++)
		for(j=1;j<=Q.nu;j++)
		{
			pm=M.rhead[i];
			pn=N.chead[j];
			e=0;
			while(pm&&pn)
				switch(comp(pn->i,pm->j))
			{
case -1: pn=pn->down; // 列指針後移
	break;
case 0: e+=pm->e*pn->e; // 乘積累加
	pn=pn->down; // 行列指針均後移
	pm=pm->right;
	break;
case 1: pm=pm->right; // 行指針後移
			}
			if(e) // 值不爲0
			{
				pq=(OLink)malloc(sizeof(OLNode)); // 生成結點
				if(!pq) // 生成結點失敗
					exit(OVERFLOW);
				pq->i=i; // 給結點賦值
				pq->j=j;
				pq->e=e;
				InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
			}
		}
		if(Q.tu==0) // Q矩陣元素個數爲0
			DestroySMatrix(Q); // 銷燬矩陣Q
}
void TransposeSMatrix(CrossList M,CrossList &T)
{ // 初始條件:稀疏矩陣M存在。操作結果:求稀疏矩陣M的轉置矩陣T
	int u,i;
	OLink *head,p,q,r;
	CopySMatrix(M,T); // T=M
	u=T.mu; // 交換T.mu和T.nu
	T.mu=T.nu;
	T.nu=u;
	head=T.rhead; // 交換T.rhead和T.chead
	T.rhead=T.chead;
	T.chead=head;
	for(u=1;u<=T.mu;u++) // 對T的每一行
	{
		p=T.rhead[u]; // p爲行表頭
		while(p) // 沒到表尾,對T的每一結點
		{
			q=p->down; // q指向下一個結點
			i=p->i; // 交換.i和.j
			p->i=p->j;
			p->j=i;
			r=p->down; // 交換.down和.right
			p->down=p->right;
			p->right=r;
			p=q; // p指向下一個結點
		}
	}
}



// main5-4.cpp 檢驗bo5-4.cpp的主程序
#include"c1.h"
typedef int ElemType;
#include"c5-4.h"
#include"bo5-4.cpp"
void main()
{
	CrossList A,B,C;
	InitSMatrix(A); // CrossList類型的變量在初次使用之前必須初始化
	InitSMatrix(B);
	printf("創建矩陣A: ");
	CreateSMatrix(A);
	PrintSMatrix(A);
	printf("由矩陣A複製矩陣B: ");
	CopySMatrix(A,B);
	PrintSMatrix(B);
	DestroySMatrix(B); // CrossList類型的變量在再次使用之前必須先銷燬
	printf("銷燬矩陣B後,矩陣B爲\n");
	PrintSMatrix1(B);
	printf("創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲%d,%d)\n",A.mu,A.nu);
	CreateSMatrix(B);
	PrintSMatrix1(B);
	printf("矩陣C1(A+B):\n");
	AddSMatrix(A,B,C);
	PrintSMatrix1(C);
	DestroySMatrix(C);
	printf("矩陣C2(A-B):\n");
	SubtSMatrix(A,B,C);
	PrintSMatrix1(C);
	DestroySMatrix(C);
	printf("矩陣C3(A的轉置):\n");
	TransposeSMatrix(A,C);
	PrintSMatrix1(C);
	DestroySMatrix(A);
	DestroySMatrix(B);
	DestroySMatrix(C);
	printf("創建矩陣A2: ");
	CreateSMatrix(A);
	PrintSMatrix1(A);
	printf("創建矩陣B3:(行數應與矩陣A2的列數相同=%d)\n",A.nu);
	CreateSMatrix(B);
	PrintSMatrix1(B);
	printf("矩陣C5(A×B):\n");
	MultSMatrix(A,B,C);
	PrintSMatrix1(C);DestroySMatrix(A);
	DestroySMatrix(B);
	DestroySMatrix(C);
}

代碼運行結果:

創建矩陣A: 請輸入稀疏矩陣的行數列數非零元個數: 3 3 2
請按任意次序輸入2個非零元的行列元素值:
2 1 2
1 2 1
3行3列2個非零元素(見圖515)
請輸入選擇(1.按行輸出2.按列輸出): 1
1行2列值爲1
2行1列值爲2
由矩陣A複製矩陣B: 3行3列2個非零元素
請輸入選擇(1.按行輸出2.按列輸出): 2
2行1列值爲2
1行2列值爲1
銷燬矩陣B後,矩陣B爲
創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲3,3)
請輸入稀疏矩陣的行數列數非零元個數: 3 3 2
請按任意次序輸入2個非零元的行列元素值:
2 2 5
1 2 -1
0 -1 0
0 5 0
0 0 0
矩陣C1(A+B):
0 0 0
2 5 0
0 0 0
矩陣C2(A-B):
0 2 0
2 -5 0
0 0 0
矩陣C3(A的轉置):

0 2 0
1 0 0
0 0 0
創建矩陣A2: 請輸入稀疏矩陣的行數列數非零元個數: 2 3 2
請按任意次序輸入2個非零元的行列元素值:
1 1 1
2 3 2
1 0 0
0 0 2
創建矩陣B3:(行數應與矩陣A2的列數相同=3)
請輸入稀疏矩陣的行數列數非零元個數: 3 2 2
請按任意次序輸入2個非零元的行列元素值:

2 2 1
3 1 2
0 0
0 1
2 0
矩陣C5(A×B):
0 0
4 0

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