稀疏矩阵的应用
此设计实现在三元组,十字链表下的稀疏矩阵的加、转、乘的实现。
1.稀疏矩阵的存储
2.稀疏矩阵的加法
3.矩阵乘法
4.矩阵转置
一:存储结构设计
采用三元组结构和十字链表结构存储稀疏矩阵的具体信息。其中:在三元组中,所有元素的信息用数组表示,每个数组元素中包含有行下标(i),列下标(j)和对应的数值(e),它们是整型数据,全部的信息用在十字链表中,全部结点的信息用结构体(TSMatrix)包含,包括用数组(Triple data[MAXSIZE])和总共的行数(mu),列数(nu)以及非零元素的个数(tu)。在十字链表下,头结点为指针数组的十字链表存储;每个结点里面包含行下标(i),列下标(j)和对应的数值(e),它们是整型数据,还有两个指针(right)、(down),属于OLNode结构体。全部的信息用结构体(crosslist)包含,包括指针数组(OLink* rhead和*chead)和总共的行数(mu),列数(nu)以及非零元素的个数(tu)。
三元组结构体定义:
typedef struct{
int i,j;
int e;
}Triple;
typedef struct{
Triple data[MAXSIZE];
int rpos[MAXSIZE + 1];
int nu,mu,tu;
}TSMatrix;
十字链表结构体定义:
typedef struct OLNode{
int i,j;
int e;
struct OLNode *right,*down;
}OLNode,*OLink;
typedef struct {
int mu,nu,tu;
OLink *rhead,*chead;
}CrossList;
十字链表结构体定义:
typedef struct OLNode{
int i,j;
int e;
struct OLNode *right,*down;
}OLNode,*OLink;
typedef struct {
int mu,nu,tu;
OLink *rhead,*chead;
}CrossList;
二:系统功能设计
本系统除了要完成分别在三元组存储结构以及在十字链表下实现稀疏矩阵的初始化功能外还设置了4个子功能菜单。稀疏矩阵的建立及初始化在三元组存储结构下,由函数 void CreateSMatrix(TSMatrix &M)实现,在十字链表存储结构下,由函数voidCreateSMatix_OL(CrossList &M)依据读入的行数和列数以及非零元素的个数,分别设定每个非零元素的信息。4个子功能的设计描述如下。
(1)稀疏矩阵的转置:
此功能在三元组存储结构下,由函数void TransposeSMatrix(TSMatrix M,TSMatrix &T)实现,在十字链表存储结构下,由函数void TurnSMatrix_OL(CrossList &M)实现。当用户选择该功能,系统提示用户初始化一个矩阵,然后进行转置,最终输出结果。
(2)稀疏矩阵的加法:
此功能在三元组存储结构下,由函数void AddTMatix(TSMatrixM,TSMatrix T,TSMatrix &S)实现,在十字链表存储结构下,由函数int SMatrix_ADD(CrossList *A,CrossList *B)实现。当用户选择该功能,系统即提示用户初始化要进行加法的两个矩阵的信息。然后进行加法,最后输出结果。
(3)稀疏矩阵的乘法:
此功能在三元组存储结构下,由函数int MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix&Q)实现。在十字链表存储结构下,由函数int MultSMatrix_OL(CrossList M, CrossList N, CrossList&Q)实现。当用户选择该功能,系统提示输入要进行相乘的两个矩阵的详细信息。然后进行相乘,最后得到结果。
(4)退出:
即退出稀疏矩阵的应用系统,由exit(0)函数实现。当用户选择该功能,则退出该稀疏矩阵的应用系统。
源代码:
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
int num[100];
typedef struct OLNode{
int i,j;
int e;
struct OLNode *right,*down;
}OLNode,*OLink;
typedef struct {
int mu,nu,tu;
OLink *rhead,*chead;
}CrossList; //十字链表结构体定义
typedef struct{
int i,j;
int e;
}Triple;
typedef struct{
Triple data[MAXSIZE];
int rpos[MAXSIZE + 1];
int nu,mu,tu;
}TSMatrix; //三元组结构体定义;
int CreateSMatix_OL(CrossList &M){
int i,j,e;
OLink q;
OLink p;
printf("请输入稀疏矩阵的行数,列数,非零元素的个数:"); //矩阵行数,列数下标均从开始;
scanf("%d%d%d",&M.mu,&M.nu,&M.tu);
M.rhead=(OLink *)malloc((M.mu+1)*sizeof(OLNode));//分配内存空间
M.chead=(OLink *)malloc((M.nu+1)*sizeof(OLNode));//分配内存空间
for( i=1;i<=M.mu;i++)M.rhead[i]=NULL;//把矩阵每个元素置空值
for( i=1;i<=M.nu;i++)M.chead[i]=NULL;
printf("请输入稀疏矩阵,如果行为0,则退出\n");
scanf("%d%d%d",&i,&j,&e);
while(i!=0){
p=(OLink)malloc(sizeof(OLNode));
p->i=i;p->j=j;p->e=e;
if(M.rhead[i]==NULL||M.rhead[i]->j>j){p->right=M.rhead[i];M.rhead[i]=p;}
else{
q=M.rhead[i];
while(q->right&&q->right->j<j)q=q->right;
p->right=q->right;
q->right=p;}
if(M.chead[j]==NULL||M.chead[j]->i>i){p->down=M.chead[j];M.chead[j]=p;}
else{
q=M.chead[j];
while(q->down&&q->down->i<i)q=q->down;
p->down=q->down;
q->down=p;
}
scanf("%d%d%d",&i,&j,&e);
}
return 1;
}//创建十字链表
void CreateSMatrix(TSMatrix &M){
//采用三元组顺序表存储表示,创建稀疏矩阵M
printf("请输入稀疏矩阵的行数、列数和非零元个数:");
scanf("%d%d%d",&M.mu,&M.nu,&M.tu);
if((M.mu<=0)||(M.nu<=0)||(M.tu<=0)||(M.tu>M.mu*M.nu))
//判断行值、列值、元素个数是否合法
printf("输入有误!");
for(int i=1;i<=M.tu;i++){//输入稀疏矩阵元素
printf("请输入元素坐标(所在行,所在列)及大小:");
scanf("%d%d%d",&M.data[i].i,&M.data[i].j,&M.data[i].e);
if((M.data[i].i<=0)||(M.data[i].j<=0)){
printf("输入错误,请重新输入");
scanf("%d%d%d",&M.data[i].i,&M.data[i].j,&M.data[i].e);
}//if
}//for i
int num[100];
if(M.tu)
{int i;
for(i = 1; i <= M.mu; i++) num[i] = 0;//初始化
for(int t = 1; t <= M.tu; t++) ++num[M.data[t].i];//求M中每一行含非零元素个数
//求rpos
M.rpos[1] = 1;
for(i = 2; i <= M.mu; i++) M.rpos[i] = M.rpos[i-1] + num[i-1];
}
}//创建三元组
void TransposeSMatrix(TSMatrix M,TSMatrix &T){
T.nu=M.mu;//T矩阵存放转置后的矩阵
T.mu=M.nu;
T.tu=M.tu;
int q=1;
for(int col=1;col<=M.nu;col++)//通过循环,把非零元素的行数与列数进行交换,实现转置
for(int 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++;
}
}//三元组转置
int Compare(int a1,int b1,int a2,int b2){
if(a1>a2)return 1;
else if(a1<a2)return -1;
else if(b1>b2)return 1;
if(b1<b2)return -1;
else return 0;
}
void AddTMatix(TSMatrix M,TSMatrix T,TSMatrix &S){//矩阵S存放相加后的矩阵
S.mu=M.mu>T.mu?M.mu:T.mu;//对S矩阵的行数赋值
S.nu=M.nu>T.nu?M.nu:T.nu;//对S矩阵的列数赋值
S.tu=0;
int ce;
int q=1;int mcount=1,tcount=1;
while(mcount<=M.tu&&tcount<=T.tu){
switch(Compare(M.data[mcount].i,M.data[mcount].j,T.data[tcount].i,T.data[tcount].j))
//用switch分支语句,用compare函数对需要相加的两个矩阵的某元素行数列数进行比较
{case -1: S.data[q].e=M.data[mcount].e;//当M.data[mcount].i<T.data[tcount].i或M.data[mcount].j<T.data[tcount].j
S.data[q].i=M.data[mcount].i;
S.data[q].j=M.data[mcount].j;//把第一个矩阵的行数i,列数j赋值给S矩阵的行数i,列数j
q++;
mcount++;
break;
case 1: S.data[q].e=T.data[tcount].e;//当M.data[mcount].i>T.data[tcount].i或M.data[mcount].j>T.data[tcount].j
S.data[q].i=T.data[tcount].i;
S.data[q].j=T.data[tcount].j;//把第二个矩阵的行数i,列数j赋值给S矩阵的行数i,列数j
q++;
tcount++;
break;
case 0: ce=M.data[mcount].e+T.data[tcount].e;//其他情况下把两个矩阵的值相加
if(ce){ S.data[q].e=ce;
S.data[q].i=M.data[mcount].i;
S.data[q].j=M.data[mcount].j;
q++;
mcount++;
tcount++;}
else {mcount++;
tcount++;}
break;
}}
while(mcount<=M.tu){
S.data[q].e=M.data[mcount].e;
S.data[q].i=M.data[mcount].i;
S.data[q].j=M.data[mcount].j;
q++;
mcount++; }//在case=-1的情况下对S矩阵的非零值,行数,列数进行赋值
while(tcount<=M.tu){
S.data[q].e=T.data[tcount].e;
S.data[q].i=T.data[tcount].i;
S.data[q].j=T.data[tcount].j;
q++;
tcount++;
}//在case=1的情况下对S矩阵的非零值,行数,列数进行赋值
S.tu=q-1;
}//三元组相加
int MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
{
int arow, brow, ccol, i, t, ctemp[100], p, q, tp;//定义相乘函数中所需要用到的变量
if(M.nu != N.mu) return 0;//如果第一个矩阵的行数不等于第二个矩阵的列数,则退出
Q.mu = M.mu, Q.nu = N.nu, Q.tu = 0;//三元组结构类型Q存放相乘后的结果
if(M.tu * N.tu != 0)//如果两个矩阵元素相乘不为零,则进行运算
{
for(arow = 1; arow <= M.mu; ++arow)//最外侧循环以矩阵行数作为循环变量
{
for(i = 0; i <= N.nu; ++i) ctemp[i] = 0;
Q.rpos[arow] = Q.tu + 1;
if(arow < M.mu) tp = M.rpos[arow + 1];
else tp = M.tu +1;
for(p = M.rpos[arow]; p < tp; ++p)//把每行与每列相乘
{
brow = M.data[p].j;
if(brow < N.mu) t = N.rpos[brow+1];
else t = N.tu + 1;
for(q = N.rpos[brow]; q < t; ++q)
{
ccol = N.data[q].j;
ctemp[ccol] += M.data[p].e * N.data[q].e;//值相乘
}
}
for(ccol = 1; ccol <= Q.nu; ++ccol) //把运算后的结果存放到Q中
{
if(ctemp[ccol])
{
if(++(Q.tu) > MAXSIZE) return 1;
Q.data[Q.tu].i = arow, Q.data[Q.tu].j = ccol, Q.data[Q.tu].e = ctemp[ccol];
}
}
}
}
return 1;
}//三元组相乘
void ShowTMatrix(TSMatrix M){
for(int col=1;col<=M.mu;col++)//通过双重循环,把稀疏矩阵中不为零的元素的行数、列数和值显示出来
for(int p=1;p<=M.tu;p++)
if(M.data[p].i==col)printf("%4d %4d %4d\n",M.data[p].i,M.data[p].j,M.data[p].e);
}//三元组显示
void TurnSMatrix_OL(CrossList &M){
int col,row; //定义循环变量
OLink p,q; //定义OLink结构类型变量
for(col=1;col<=M.mu;col++) //通过循环,把非零元素的行数与列数进行交换,实现转置
{ q=p=M.rhead[col];
while(q){
row=p->i;
p->i=p->j;
p->j=row;
q=p->right;
p->right=p->down;
p->down=q;
}
}
}//十字链表转置
int SMatrix_ADD(CrossList *A,CrossList *B){
OLNode *pa,*pb,*pre,*p,*cp[100]; //定义OLNode类型的变量
int i,j,t;
t=A->tu+B->tu;
for(j=1;j<=A->nu;j++)cp[j]=A->chead[j];//将A矩阵的列表头指针赋给cp数组
for(i=1;i<=A->mu;i++){
pa=A->rhead[i];
pb=B->rhead[i];//将A,B矩阵的行表头指针分别赋给pa,pb
pre=NULL;
while(pb){//当pb不等于零
if(pa==NULL||pa->j>pb->j){
p=(OLink)malloc(sizeof(OLNode));//给p动态分配空间
if(!pre)A->rhead[i]=p;
else pre->right=p;
p->right=pa;
pre=p;
p->i=i;p->j=pb->j;p->e=pb->e;
if(!A->chead[p->j]){
A->chead[p->j]=cp[p->j]=p;
p->down=NULL;
}//如果A->chead[p->j]不等于零,则把p赋给它及cp[p->j]
else{
cp[p->j]->down=p;
cp[p->j]=p;
}
pb=pb->right;
}//否则把p赋给cp[p->j]
else if(pa->j<pb->j){pre=pa;
pa=pa->right;}
else if(pa->e+pb->e){
t--;
pa->e+=pb->e;
pre=pa;
pa=pa->right;
pb=pb->right;}
else { t=t-2;
if(!pre)A->rhead[i]=pa->right;
else pre->right=pa->right;
p=pa;pa=pa->right;
if(A->chead[p->j]==p)A->chead[p->j]=cp[p->j]=p->down;
else cp[p->j]->down=p->down;
free(p);
pb=pb->right;
}
}
}
A->mu=A->mu>B->mu?A->mu:B->mu;
A->nu=A->nu>B->nu?A->nu:B->nu;//A的行与列为A及B当中较大的一个
return 1;
}//十字链表相加
int MultSMatrix_OL(CrossList M, CrossList N, CrossList &Q)
{
int i, j, e; //中间变量
OLink p0, q0, p, pl, pla; //中间变量
if(M.nu != N.mu) //检查稀疏矩阵M的列数和N的行数是否对应相等
{
printf ( "稀疏矩阵A的列数和B的行数不相等,不能相乘。\n" );
return 0;
}
Q.mu = M.mu, Q.nu = N.nu, Q.tu = 0;
if(!(Q.rhead = (OLink *)malloc((Q.mu + 1) * sizeof(OLink)))) exit(-2);
if(!(Q.chead = (OLink *)malloc((Q.nu + 1) * sizeof(OLink)))) exit(-2);
for(i = 1; i <= Q.mu; i++) Q.rhead[i] = NULL;
for(i = 1; i <= Q.nu; i++) Q.chead[i] = NULL;
//相乘
for(i =1; i <= Q.mu; i++)
for(j = 1; j <= Q.nu; j++)
{
p0 = M.rhead[i], q0 = N.chead[j], e = 0;
while(p0&&q0) //M第i行和N第j列有元素
{
if( p0->j > q0->i) q0 = q0->down; //M的列大于N的行,则N的列指针后移
else if(p0->j < q0->i) p0 = p0->right;//M的列小于N的行,则M的行指针右移
else { //M的行等于N的列
e += p0->e * q0->e; //乘积累加
q0 = q0->down, p0 = p0->right; //移动指针
}
}
if(e) //乘积不为
{
if(!(p = (OLink)malloc(sizeof(OLNode)))) exit(-2);
Q.tu++;//非零元素增加
p->i = i, p->j = j, p->e = e, p->right = NULL, p->down = NULL;//赋值,指针后移
//将p插入十字链表
//行插入
if(Q.rhead[i] == NULL) //若p为该行的第个结点
Q.rhead[i] = pl = p; //p插在该行的表头且pl指向p(该行的最后一个结点)
else pl->right = p, pl = p; //插在pl所指结点之后,pl右移
//列插入
if(Q.chead[j] == NULL) //若p为该列的第一个结点
Q.chead[j] = p; //该列的表头指向p
else {//插在列表尾
pla = Q.chead[j];//pla指向j行的第个结点
while(pla->down) pla = pla->down;//pla指向j行最后一个结点
pla->down = p;
}
}
}
return 1;
}//十字链表相乘
int ShowMAtrix(CrossList *A){
int col;
OLink p;
for(col=1;col<=A->mu;col++)if(A->rhead[col]){p=A->rhead[col];
while(p){printf("%3d%3d%3d\n",p->i,p->j,p->e);p=p->right;}
}
return 1;
}//十字链表显示
void main(){
int n,i;
char b;
TSMatrix M,T,S;
CrossList MM,TT,SS;
printf(" ***稀疏矩阵应用***");
printf("\n请你选择创建稀疏矩阵的方法:\n1:用三元组创建稀疏矩阵\n2:用十字链表创建稀疏矩阵\n3:退出程序");
printf("\n");
scanf("%d",&n);
switch(n){
case 1:
CreateSMatrix(M);
printf("您输入的稀疏矩阵为(只列出非零元素):\n 行 列 大小\n");
ShowTMatrix(M);
printf("已经选择三元组创建稀疏矩阵,请选择操作:\n1:稀疏矩阵转置\n2:稀疏矩阵相加\n3:稀疏矩阵相乘\n4:退出程序\n");
scanf("%d",&i);
switch(i){
case 1:TransposeSMatrix(M,T);
printf("转置后的矩阵为(只列出非零元素):\n 行 列 大小\n");
ShowTMatrix(T);
break;
case 2:printf("请你输入另一个稀疏矩阵:");
CreateSMatrix(T);
AddTMatix(M,T,S);
printf("相加后的矩阵为(只列出非零元素):\n 行 列 大小\n");
ShowTMatrix(S);
break;
case 3:printf("请你输入另一个稀疏矩阵:");
CreateSMatrix(T);
MultSMatrix(M,T,S);
printf("相乘后的矩阵为(只列出非零元素):\n 行 列 大小\n");
ShowTMatrix(S);
break;
case 4:
exit(0);};break;
case 2:{CreateSMatix_OL(MM);
printf("您输入的稀疏矩阵为(只列出非零元素):\n 行 列大小\n");
ShowMAtrix(&MM);
printf("已经选择十字链表创建稀疏矩阵,请选择操作:\n1:稀疏矩阵转置\n2:稀疏矩阵相加\n3:稀疏矩阵相乘\n4:退出程序\n");
scanf("%d",&i);
switch(i){
case 1:
TurnSMatrix_OL(MM);
printf("转置后的矩阵为(只列出非零元素):\n 行 列大小\n");
ShowMAtrix(&MM);
break;
case 2:
printf("请你输入另一个稀疏矩阵:");
CreateSMatix_OL(TT);
SMatrix_ADD(&MM,&TT);
printf("相加后的矩阵为(只列出非零元素):\n 行 列大小\n");
ShowMAtrix(&MM);break;
case 3:printf("请你输入另一个稀疏矩阵:");
CreateSMatix_OL(TT);
MultSMatrix_OL(MM,TT,SS);
printf("相乘后的矩阵为(只列出非零元素):\n 行 列大小\n");
ShowMAtrix(&SS);break;
case 4:exit(0);
}};break;
case 3:exit(0);
default :printf("erorr");
}
}
(注:此次的设计是我们学校的数据结构课程设计实验,这是我通过网络与书籍共同完成的,希望专家指点,有什么问题尽管提,对的一定改正.欢迎评论!)