• 矩阵的压缩存储(稀疏矩阵的十字链表存储、稀疏矩阵的三元组行逻辑链接的顺序表存储表示、稀疏矩阵的三元组顺序表存储表示)


    // 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个非零元素。
    ",M.mu,M.nu,M.tu);
    	printf("行列元素值
    ");
    	for(i=1;i<=M.tu;i++)
    		printf("%2d%4d%8d
    ",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("
    ");
    	}
    }
    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:
    ");
    	CopySMatrix(A,B);
    	PrintSMatrix1(B);
    	DestroySMatrix(B);
    	printf("销毁矩阵B后:
    ");
    	PrintSMatrix1(B);
    	printf("创建矩阵B2:(与矩阵A的行、列数相同,行、列分别为%d,%d)
    ",A.mu,A.nu);
    	CreateSMatrix(B);
    	PrintSMatrix1(B);
    	AddSMatrix(A,B,C);
    	printf("矩阵C1(A+B):
    ");
    	PrintSMatrix1(C);
    	SubtSMatrix(A,B,C);
    	printf("矩阵C2(A-B):
    ");
    	PrintSMatrix1(C);
    	TransposeSMatrix(A,C);
    	printf("矩阵C3(A的转置):
    ");
    	PrintSMatrix1(C);
    	printf("创建矩阵A2: ");
    	CreateSMatrix(A);
    	PrintSMatrix1(A);
    	printf("创建矩阵B3:(行数应与矩阵A2的列数相同=%d)
    ",A.nu);
    	CreateSMatrix(B);
    	PrintSMatrix1(B);
    	MultSMatrix(A,B,C);
    	printf("矩阵C5(A×B):
    ");
    	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的快速转置):
    ");
    	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个非零元素。
    ",M.mu,M.nu,M.tu);
    	printf("行列元素值
    ");
    	for(i=1;i<=M.tu;i++)
    		printf("%2d%4d%8d
    ",M.data[i].i,M.data[i].j,M.data[i].e);
    	for(i=1;i<=M.mu;i++)
    		printf("第%d行的第一个非零元素是本矩阵第%d个元素
    ",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("
    ");
    	}
    }
    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:
    ");
    	CopySMatrix(A,B);
    	PrintSMatrix1(B);
    	DestroySMatrix(B);
    	printf("销毁矩阵B后:
    ");
    	PrintSMatrix1(B);
    	printf("创建矩阵B2:(与矩阵A的行、列数相同,行、列分别为%d,%d)
    ",A.mu,A.nu);
    	CreateSMatrix(B);
    	PrintSMatrix1(B);
    	AddSMatrix(A,B,C);
    	printf("矩阵C1(A+B):
    ");
    	PrintSMatrix1(C);
    	SubtSMatrix(A,B,C);
    	printf("矩阵C2(A-B):
    ");
    	PrintSMatrix1(C);
    	TransposeSMatrix(A,C);
    	printf("矩阵C3(A的转置):
    ");
    	PrintSMatrix1(C);
    	printf("创建矩阵A2:
    ");
    	CreateSMatrix(A);
    	PrintSMatrix1(A);
    	printf("创建矩阵B3:(行数应与矩阵A2的列数相同=%d)
    ",A.nu);
    	CreateSMatrix(B);
    	PrintSMatrix1(B);
    	MultSMatrix(A,B,C);
    	printf("矩阵C5(A×B):
    ");
    	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个非零元的行列元素值:
    ",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个非零元素
    ",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("
    ");
    	}
    }
    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("两个矩阵不是同类型的,不能相加
    ");
    		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("两个矩阵不是同类型的,不能相减
    ");
    		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为
    ");
    	PrintSMatrix1(B);
    	printf("创建矩阵B2:(与矩阵A的行、列数相同,行、列分别为%d,%d)
    ",A.mu,A.nu);
    	CreateSMatrix(B);
    	PrintSMatrix1(B);
    	printf("矩阵C1(A+B):
    ");
    	AddSMatrix(A,B,C);
    	PrintSMatrix1(C);
    	DestroySMatrix(C);
    	printf("矩阵C2(A-B):
    ");
    	SubtSMatrix(A,B,C);
    	PrintSMatrix1(C);
    	DestroySMatrix(C);
    	printf("矩阵C3(A的转置):
    ");
    	TransposeSMatrix(A,C);
    	PrintSMatrix1(C);
    	DestroySMatrix(A);
    	DestroySMatrix(B);
    	DestroySMatrix(C);
    	printf("创建矩阵A2: ");
    	CreateSMatrix(A);
    	PrintSMatrix1(A);
    	printf("创建矩阵B3:(行数应与矩阵A2的列数相同=%d)
    ",A.nu);
    	CreateSMatrix(B);
    	PrintSMatrix1(B);
    	printf("矩阵C5(A×B):
    ");
    	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

  • 相关阅读:
    程序员的希波克拉底誓言[精华]
    怎样成为优秀的软件模型设计者
    C#中Delegate浅析与思考
    程序员是一个美好的职业[精华]
    hdu 1421(搬寝室)
    hdu 4022(map一对多)
    hdu 1114(完全背包)
    hdu 1159(最长公共子序列)
    hdu 2844(多重背包)
    hdu 1257(最长递增子序列)
  • 原文地址:https://www.cnblogs.com/KongkOngL/p/3945951.html
Copyright © 2020-2023  润新知