用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料.docx
《用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料.docx》由会员分享,可在线阅读,更多相关《用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料.docx(34页珍藏版)》请在冰豆网上搜索。
用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料
#include
#include
#defineSize2501
#defineSize151
typedefstruct
{
inti;
intj;
inte;//非零元的值
}triple;//定义三元组
typedefstruct
{
tripledata[Size+1];//矩阵中的元素
introps[Size1+1];//rops[i]为第i行元素中的首非零元在data[]中的序号
intmu;//行数
intnu;//列数
inttu;//非零元数
}juzhen;//定义矩阵
typedefstructnode//定义十字链表元素
{
inti,j,e;
structnode*right,*down;//该非零元所在行表和列表的后继元素
}node,*link;
typedefstruct//定义十字链表对象结构体
{
link*rhead,*chead;//行和列的头指针
intm,n,t;//系数矩阵的行数,列数,和非零元素个数
}crosslist;
voidcreatecross(crosslist&M)//建立十字链表
{
inti,j,e,k;
node*p,*q;
printf("输入行,列和非零元数,空格隔开:
\n");
scanf("%d%d%d",&M.m,&M.n,&M.t);
M.rhead=(link*)malloc((M.m+1)*sizeof(link));//给行和列的头指针分配内存
M.chead=(link*)malloc((M.n+1)*sizeof(link));
for(k=1;k<=M.m;k++)//初始化行,列的头指针
M.rhead[k]=NULL;
for(k=1;k<=M.n;k++)
M.chead[k]=NULL;
printf("输入非零元的行,列和值,空格隔开:
\n");
for(k=1;k<=M.t;k++)//输入非零元
{
scanf("%d%d%d",&i,&j,&e);
p=(node*)malloc(sizeof(node));
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
{
for(q=M.rhead[i];(q->right)&&q->right->jright);//空循环找到第一个列标大于或等于插入元素列标的元素
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
{
for(q=M.chead[j];(q->down)&&q->down->idown);//空循环找到第一个行标大于或等于插入元素行标的元素
p->down=q->down;
q->down=p;
}
}
}
voidprintcross(crosslistA)//输出十字链表
{
if(A.m==0)
printf("十字链表为空!
\n");
else
{
printf("十字链表为:
\n");
inti,j;
for(i=1;i<=A.m;i++)
{
linkp=A.rhead[i];
for(j=1;j<=A.n;j++)
{
if((p)&&(j==p->j))
{
printf("%5d",p->e);
p=p->right;}
else
printf("%5d",0);
}
printf("\n");
}
}
printf("\n");
}
crosslistaddcross()
{
printf("十字链表加法:
\n");
crosslista,b;//创建两个十字链表对象,并初始化
createcross(a);
createcross(b);
node*pre,*h[51],*pa,*pb,*q;//定义辅助指针,pa,pb分别为a,b当前比较的元素,pre为pa的前驱元素
inti,j,k=0,m,n;//h[j]指向j列的当前插入位置
if(a.m!
=b.m||a.n!
=b.n)
printf("格式不对,不能相加!
\n");
else
{
for(i=1;i<=a.m;i++)
{
pa=a.rhead[i];
pb=b.rhead[i];
pre=NULL;
for(j=1;j<=a.n;j++)
h[j]=NULL;
while(pb)
{
linkp;
p=(node*)malloc(sizeof(node));//开辟新节点,存储b中取出的元素
p->i=pb->i;
p->j=pb->j;
p->e=pb->e;
if(pa==NULL||pa->j>pb->j)//当a此行已经检查完或者pb因该放在pa前面
{
if(pre==NULL)
a.rhead[p->i]=p;
else
pre->right=p;
p->right=pa;
pre=p;
if(h[p->j]==NULL)//当前插入位置下面无非零元
//因为是逐行处理,so,h[p->j],依次下移
//因此每次都是指向插入的位置
{
a.chead[p->j]=p;
p->down=NULL;
}
else
{
p->down=h[p->j]->down;
h[p->j]->down=p;
}
h[p->j]=p;//*******h[p->j]下移指向下次插入的位置
pb=pb->right;//pb指向该行下个元素
}
elseif((pa&&pa->jj))//只要移动pa的指针****先不加||(pb==NULL&&pa)
{
pre=pa;
h[pa->j]=pa;//移动h[],使其指向下次插入的位置
pa=pa->right;
}
elseif(pa->j==pb->j)
{
pa->e+=pb->e;
if(pa->e)//不为零
{
pre=pa;
h[pa->j]=pa;
pb=pb->right;//加
}
else//pa->e为零,删除节点
{
if(pre==NULL)
a.rhead[pa->i]=pa->right;
else
{
pre->right=pa->right;
}
p=pa;//p指向pa,用来在下面修改列指针
pa=pa->right;
if(h[p->j]==NULL)
a.chead[p->j]=p->down;
else
{
h[p->j]->down=p->down;
}
free(p);
pb=pb->right;
}
}
}
}
}
returna;
}
voidmultycross(crosslist&c)//十字链表乘法
{
node*p,*q,*u,*v,*p1,*p2;
crosslista,b;
link*r;
inti,j,k,e;
printf("十字链表乘法:
\n");
createcross(a);
createcross(b);
if(a.n!
=b.m)
printf("格式错误,不能相乘!
\n");
else
{
c.m=a.m;
c.n=b.n;
c.t=0;
c.rhead=(link*)malloc((a.m+1)*sizeof(link));//给行和列的头指针分配内存
c.chead=(link*)malloc((b.n+1)*sizeof(link));
for(k=1;k<=a.m;k++)//初始化行,列的头指针
c.rhead[k]=NULL;
for(k=1;k<=b.n;k++)
c.chead[k]=NULL;
r=(link*)malloc((b.n+1)*sizeof(link));
for(i=1;i<=a.m;i++)
{
u=(node*)malloc(sizeof(node));
u->e=0;
u->i=0;
u->j=0;
for(k=1;k<=b.n;k++)//初始化r[]
r[k]=u;
p1=p=a.rhead[i];
for(j=1;j<=b.n;j++)
{
p=p1;
q=b.chead[j];
v=(node*)malloc(sizeof(node));//初始化v,v为将插入c矩阵的元素
v->e=0;
v->i=i;
v->j=j;
while(p&&q)
{
if(p->j>q->i)
q=q->down;
elseif(p->ji)
p=p->right;
else
{
v->e+=p->e*q->e;
p=p->right;
q=q->down;
}
}
if(v->e)//如果不为零,则插入c矩阵中
{
//同建立十字链表
if(c.rhead[i]==NULL||c.rhead[i]->j>j)//插入元素所在行无非零元或首非零元的列标大于插入元素的列标
{
v->right=c.rhead[i];
c.rhead[i]=v;
}
else
{
for(p2=c.rhead[i];(p2->right)&&(p2->right->jright);//空循环找到第一个列标大于或等于插入元素列标的元素
v->right=p2->right;
p2->right=v;
}
if(c.chead[j]==NULL||c.chead[j]->i>i)//插入元素所在列无非零元或首非零元的行标大于插入元素的行标
{
v->down=c.chead[j];
c.chead[j]=v;
}
else
{
for(p2=c.chead[j];(p2->down)&&(p2->down->idown);//空循环找到第一个行标大于或等于插入元素行标的元素
v->down=p2->down;
p2->down=v;
}
}
}
}
}
}
voidcreate(juzhen&M)//创建稀疏矩阵
{
inti,t=0;
printf("输入矩阵行数和列数and非零元的个数,以空格隔开:
\n");
scanf("%d%d%d",&M.mu,&M.nu,&M.tu);
printf("输入矩阵非零元的行,列,和数值(中间空格隔开):
\n");
for(i=1;i<=M.tu;i++)
scanf("%d%d%d",&M.data[i].i,&M.data[i].j,&M.data[i].e);//输入三元组的元素
for(i=1;i<=Size1;i++)//初始化rops【】
M.rops[i]=0;
for(i=1,t=1;i<=M.mu;i++)//得到各行第一个元素的序号
{
M.rops[i]=t;
while(M.data[t].i<=i&&t<=M.tu)//遇到i行非零元,则t累加
t++;
}
}
voidadd(juzhenA,juzhenB,juzhen&C)//稀疏矩阵加法
{
intk=1,temp=0,k1=1,k2=1;//k1,k2,k分别控制A,B,C中非零元的序号变化
printf("稀疏矩阵加法:
\n");
create(A);
create(B);
if(A.mu!
=B.mu||A.nu!
=B.nu)
printf("格式不对,不能相加!
\n");
else
{
while(k1<=A.tu&&k2<=B.tu)//当A,B中的非零元都没用完
{
if(A.data[k1].iC.data[k++]=A.data[k1++];
elseif(A.data[k1].i>B.data[k2].i)//同上
C.data[k++]=B.data[k2++];
else//data[k1],data[k2]行标相同
{
if(A.data[k1].j>B.data[k2].j)//data[k1]列标大于data[k2]列标,则把data[k2]的值赋给data[k]
C.data[k++]=B.data[k2++];
elseif(A.data[k1].jC.data[k++]=A.data[k1++];
else//行,列标都相同
{
temp=0;
temp=A.data[k1].e+B.data[k2].e;
if(temp)//相加后不为零
{
C.data[k].i=A.data[k1].i;
C.data[k].j=A.data[k1].j;
C.data[k].e=temp;
k++;
}
k1++;
k2++;
}
}
}
while(k1<=A.tu)//B中非零元已用完,A中还有非零元
C.data[k++]=A.data[k1++];
while(k2<=B.tu)//A中非零元已用完,B中还有非零元
C.data[k++]=B.data[k2++];
C.mu=A.mu;//确定C的行列数和非零元个数
C.nu=A.nu;
C.tu=k-1;
}
}
voidprint(juzhenA)//输出稀疏矩阵
{
printf("\n矩阵为:
\n");
inti,j,k=1;
if(A.mu==0)
printf("矩阵为空!
\n");
elseif(A.tu==0)//矩阵元素为空
printf("零矩阵!
\n");
else
for(i=1;i<=A.mu;i++)//逐行输出
{
for(j=1;j<=A.nu;j++)
{
if(A.data[k].i==i&&A.data[k].j==j)//行和列分别对应相等则输出相应非零元,否则输出零
printf("%5d",A.data[k++].e);
else
printf("%5d",0);
}
printf("\n");//该行输出结束,空行输出下一行
}
printf("\n");
}
voidmulty(juzhenA,juzhenB,juzhen&C)//稀疏矩阵乘法
{
intarow,brow,ccol,temp[51],p,q,t,tp,i;//各变量代表含义见下面
printf("稀疏矩阵乘法:
\n");
create(A);
create(B);
if(A.nu!
=B.mu)
printf("格式错误,不能相乘!
\n");
else
{
C.mu=A.mu;//初始化c的行列及非零元个数
C.nu=B.nu;
C.tu=0;
if(A.nu!
=B.mu)
printf("A,B格式不对不能相乘!
\n");
else//
{
for(arow=1;arow<=A.mu;arow++)//arow为当前A矩阵的行标
{
for(i=0;i<51;i++)//初始化temp
temp[i]=0;
if(arowtp=A.rops[arow+1];//tp为arow+1行的首非零元在data【】中的序号
else//arow为最后一行
tp=A.tu+1;
for(p=A.rops[arow];p{
brow=A.data[p].j;//brow为与B矩阵中的相应行对应的A中当前元素的列标
if(browt=B.rops[brow+1];//t为brow+1行的首非零元在B中data【】中的序号
else//brow大小等于B.mu
t=B.tu+1;
for(q=B.rops[brow];q{
ccol=B.data[q].j;//ccol:
data[p]*data[q]所得结果所在的列
temp[ccol]+=A.data[p].e*B.data[q].e;//temp【ccol】:
相乘所得的C矩阵中第arow行cool列元素的值
}
}
for(ccol=1;ccol<=B.nu;ccol++)//
if(temp[ccol])//temp【ccol】不为零,则把值赋到c中,c.tu加1。
{
C.data[++C.tu].e=temp[ccol];
C.data[C.tu].i=arow;
C.data[C.tu].j=ccol;
}
}
}
}
}
voidclear(juzhen&A)//清空稀疏矩阵
{
inti;
A.mu=0;
A.nu=0;
A.tu=0;
for(i=0;iA.rops[i]=0;
for(i=0;i{
A.data[i].i=0;
A.data[i].j=0;
A.data[i].e=0;
}
}
voidmain()
{
juzhenA,B,C,D;
crosslista,b,c,d;
lable:
printf("******************************************************************\n");
printf("请选择:
1、稀疏矩阵的加法,并输出结果,2、稀疏矩阵乘法,并输出结果\n");
printf("\n3、十字链表加法,并输出,4、十字链表乘法并输出,5、结束:
\n");
printf("******************************************************************\n");
intx;
scanf("%d",&x);
switch(x)
{
case1:
add(A,B,C);
print(C);
printf("\n");
gotolable;
case2:
multy(A,B,C);
print(C);
printf("\n");
gotolable;
case3:
a=addcross();
printcross(a);
printf("\n");
gotolable;
case4:
multycross(b);
printcross(b);
printf("\n");
gotolable;
case5:
break;
}
printf("\n");
}
/*
乘法测试数据:
矩阵原型:
4-300130024-60
00080*-420800
00100010=010
000070100000
000
456
114
12-3
151
248
331
4570
535
113
21-4
222
321
411
4520
111
121
131
141
15