数据结构课程设计十字链表.docx
《数据结构课程设计十字链表.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计十字链表.docx(14页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计十字链表.docx](https://file1.bdocx.com/fileroot1/2022-11/24/7b0d6a6c-e4dc-4820-9c42-0d9abdb811e6/7b0d6a6c-e4dc-4820-9c42-0d9abdb811e61.gif)
数据结构课程设计十字链表
中南民族大学
数据结构课程设计报告
姓名:
康宇
年级:
2010
学号:
10061014
专业:
计算机科学与技术
指导老师:
宋中山
2013年4月15日
实习报告:
十字链表
题目:
设计一个用十字链表实现稀疏矩阵相加的程序
班级:
计科一班姓名:
康宇学号:
10061014完成日期:
2013.4.15
一、需求分析
1、十字链表分析:
当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表。
例如,在作“将矩阵B加到矩阵A上”的操作时,由于非零元的插入或删除将会引起A.data中元素的移动。
为此,对这种类型的矩阵,采用脸是存储结构表示三元组的线性表更为恰当。
2、测试数据:
两个矩阵的规模以及非零元个数都是由用户自己确定,然后有读者输入具体的非零元位置与数据域,然后输出用户输入的两个矩阵后,再把相加的矩阵输出。
3、实现提示:
在链表中,每个非零元可用一个含5个域的结点表示,其中i,j和e这三个域分别表示该非零元所在的行和列和非零元的值,向右域right用以链接同一行中下一个非零元,向下域down用以链接同一列中下一个非零元。
同一行的非零元通过right域链接成一个线性链表,同一列的非零元通过down域链接成一个线性链表,每个非零元既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表,故称这样的存储结构为十字链表,可用两个分别存储行链表的头指针和列链表的头指针的一维数组表示之。
二、概要设计
1.元素类型(栈):
typedefstructOLNode//结点类型
{
inti,j;//行列
inte;//数据域
structOLNode*right,*down;//行和列的后继域
}OLNode,*OLink;
typedefstruct//创建一个总的头结点
{
OLink*rhead,*chead;//行列链表头指针
intmu,nu,tu;//稀疏矩阵的行数,列数和非零元个数
}CrossList;
2.本程序包括四个模块:
1)主程序:
Voidmain()
{
CrossListA,B;
CreateSmatix(A);//构建矩阵A
CreateSmatix(B);//构建矩阵B
调用输出函数print(A)输出A;
调用输出函数print(B)输出B;
Add(A,B);//实现矩阵相加A+B,结果放到A中
调用输出函数print(A)输出相加后的矩阵;
}
2)矩阵构建函数:
voidCreateSmatix(CrossList&M)
{
scanf("%d%d%d",行数m,列数n,非零元个数t);
动态创建m+1个结点长的行链表指针;
动态创建n+1个结点长的列链表指针;
初始化创建的行列链表指针;
for(k=0;k{
If(输入非零结点)
{
生成结点;
If(对应的行头结点为空||头结点列元素大于结点)
插入结点;
Else
寻找在行表中的位置;
完成行插入;
If(对应的列头结点为空||头结点行元素大于结点)
插入结点;
Else
寻找在列表中的位置;
完成列插入;
}
}
}
3)矩阵输出函数:
voidprint(CrossList&M)
{
printf("\t行\t列\t值\n");
OLinkp;
for(inti=1;i{
P=行的头结点;
while(结点不空)
{
printf("\t%d\t%d\t%d\n",p->i,p->j,p->e);
p指针下移;
}
}
释放p;
}
4)矩阵相加函数:
voidAdd(CrossList&M,CrossList&N)
{
intk;
OLinkp=NULL,s=NULL;
OLinkpa,pb,pre;//pre指示pa所指结点的前驱结点
动态创建标记列结点的指针hl;
for(k=1;k<=M.nu;k++)
指针hl只想对应的列头结点;
for(k=1;k<=N.mu;k++)//每行依次处理
{
pre=NULL;
pa=M.rhead[k];//标记矩阵A的结点
pb=N.rhead[k];//标记矩阵B的结点
while(B的结点不空)
{
if(A对应的结点为空||A的列结点>B的列结点){
创建pb所指结点的复制新结点p
初始化pb;
if(pre为空)
M.rhead[p->i]=p;
else
pre->right=p;
p->right=pa;
pre=p;//pre始终指向pa的前驱结点
if(对应的列头结点不空||对应的列头结点在结点之后){
改变列结点;
p->down=M.chead[p->j];
M.chead[p->j]=p;
}
else
{
寻找该插入的位置;
插入该结点;
}
hl[p->j]=p;
}
elseif(A对应的结点不空且&&A的列结点
{
Pre与pa指针皆后移一位;
}
elseif(矩阵A,B两节点位置相等)
{
pa->e+=pb->e;
if(数据域为0)
{
if(pre为空)
直接删除该零元;
else
pre->right=pa->right;
p=pa;//利于释放
指针pa下移;
寻找列方向合适的位置;
把零结点从链表中删除,不改变原有的数据结构;
释放p;
}
}
pb指针下移;
}
}
}
三、详细设计
#include
#include
//十字链表
typedefstructOLNode
{
inti,j;//行列
inte;
structOLNode*right,*down;//行和列的后继域
}OLNode,*OLink;
typedefstruct
{
OLink*rhead,*chead;//行列链表头指针
intmu,nu,tu;//稀疏矩阵的行数,列数和非零元个数
}CrossList;
voidCreateSmatix(CrossList&M)
{
intk;
intm,n,t;
inti,j,e;
OLinkp,q;
//创建稀疏矩阵M,采用十字链表存储表示
scanf("%d%d%d",&m,&n,&t);
if(m*n{
printf("输入数据错误!
!
\n");
exit
(1);
}
M.mu=m;
M.nu=n;
M.tu=t;
if(!
(M.rhead=(OLink*)malloc((m+1)*sizeof(OLink))))
exit
(1);
if(!
(M.chead=(OLink*)malloc((n+1)*sizeof(OLink))))
exit
(1);
//各行列链表初始化为空链表
for(k=1;kM.rhead[k]=NULL;
for(k=1;kM.chead[k]=NULL;
for(k=0;k{
printf("请输入非零元:
");
if(scanf("%d%d%d",&i,&j,&e)&&i!
=0&&j!
=0)
{
if(!
(p=(OLink)malloc(sizeof(OLNode))))//生成结点
exit
(1);
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;
}//完成列插入
}
else
{
printf("输入数据错误!
!
");
exit
(1);
}
}
}
voidprint(CrossList&M)
{
printf("\t行\t列\t值\n");
OLinkp;
for(inti=1;i{
p=M.rhead[i];
while(p)
{
printf("\t%d\t%d\t%d\n",p->i,p->j,p->e);
p=p->right;
}
}
free(p);
}
voidAdd(CrossList&M,CrossList&N)
{
intk;
OLinkp=NULL,s=NULL;
OLinkpa,pb,pre;//pre指示pa所指结点的前驱结点
OLink*hl=(OLink*)malloc((M.nu+1)*sizeof(OLNode));
for(k=1;k<=M.nu;k++)
hl[k]=M.chead[k];
for(k=1;k<=N.mu;k++)//每行依次处理
{
pre=NULL;
pa=M.rhead[k];//标记矩阵A的结点
pb=N.rhead[k];//标记矩阵B的结点
while(pb)
{
if(pa==NULL||pa->j>pb->j)//情况一
{
p=(OLink)malloc(sizeof(OLNode));//创建pb所指结点的复制新结点p
p->i=pb->i;
p->j=pb->j;
p->e=pb->e;
if(pre==NULL)
M.rhead[p->i]=p;
else
pre->right=p;
p->right=pa;
pre=p;//pre始终指向pa的前驱结点
if(!
M.chead[p->j]||M.chead[p->j]->i>p->i)//改变列方向
{
p->down=M.chead[p->j];
M.chead[p->j]=p;
}
else
{
for(s=hl[p->j];(s->down)&&(s->down->ii);s=s->down);
hl[p->j]=s;
p->down=hl[p->j]->down;
hl[p->j]->down=p;
}
hl[p->j]=p;
}
elseif(pa!
=NULL&&pa->jj)//情况二
{
pre=pa;
pa=pa->right;
}
elseif(pa->j==pb->j)//情况三
{
pa->e+=pb->e;
if(pa->e==0)
{
if(pre==NULL)
M.rhead[pa->i]=pa->right;
else
pre->right=pa->right;
p=pa;//利于释放
pa=pa->right;
for(s=hl[p->j];s!
=p;s=s->down);//改变列方向
hl[p->j]=s;
if(M.chead[p->j]==p)
M.chead[p->j]=hl[p->j]=p->down;
else
hl[p->j]->down=p->down;
free(p);
}
}
pb=pb->right;
}
}
}
intmain()
{
CrossListA,B;
printf("请输入矩阵A的行数,列数和非零元个数:
");
CreateSmatix(A);//构建矩阵A
printf("请输入矩阵B的行数,列数和非零元个数:
");
CreateSmatix(B);//构建矩阵B
printf("矩阵A为:
\n");
print(A);
printf("矩阵B为:
\n");
print(B);
Add(A,B);//实现矩阵相加A+B,结果放到A中
printf("矩阵A,B相加后为:
\n");
print(A);
return0;
}
四、调试分析
1.本次作业还是有一定的难度的,核心算法在于怎样把一个数据元分别插入行链表和列链表中,并且还要插在合适的位置,确保是按正确的顺序插入的,便于查找,遍历,计算。
还有一个难点就是:
把矩阵B加到矩阵A上,有多种情况要考虑,多种边界要注意,尤其是:
两个矩阵对应的数据域相加后为零,还要把这个零元给删除,并且要不破坏原有的数据结构。
2.本程序模块简洁,在main()函数里得到充分体现,两个矩阵生成函数CreateSmatix(A)与CreateSmatix(B),还有一个矩阵相加函数Add(A,B);
3.用户可灵活控制矩阵的规模大小以及非零元个数,本程序具有一定的普遍性。
五、用户手册
1.本程序运行环境为Windows操作系统,执行文件为:
十字链表.exe
2.进入演示程序后显示的界面:
六、测试结果