数据结构关键路径及十字链表基本操作课程设计报告.docx

上传人:b****6 文档编号:6973818 上传时间:2023-01-13 格式:DOCX 页数:18 大小:90.92KB
下载 相关 举报
数据结构关键路径及十字链表基本操作课程设计报告.docx_第1页
第1页 / 共18页
数据结构关键路径及十字链表基本操作课程设计报告.docx_第2页
第2页 / 共18页
数据结构关键路径及十字链表基本操作课程设计报告.docx_第3页
第3页 / 共18页
数据结构关键路径及十字链表基本操作课程设计报告.docx_第4页
第4页 / 共18页
数据结构关键路径及十字链表基本操作课程设计报告.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

数据结构关键路径及十字链表基本操作课程设计报告.docx

《数据结构关键路径及十字链表基本操作课程设计报告.docx》由会员分享,可在线阅读,更多相关《数据结构关键路径及十字链表基本操作课程设计报告.docx(18页珍藏版)》请在冰豆网上搜索。

数据结构关键路径及十字链表基本操作课程设计报告.docx

数据结构关键路径及十字链表基本操作课程设计报告

数据结构课程设计报告

 

小组成员:

王瑞琦13052007

姜薇13052011

刘倩13052027

小组课题:

1-1有向图十字链表的操作

2-5关键路径

 

有向图十字链表的操作

功能概述

将有向图以是十字链表的形式存储,并借助十字链表对有向图进行查找有向图中指定结点的度(出度和入度)、插入有向边和删除有向边等操作。

模块简介

创建有向图十字链表:

voidcreat_crosslink(ALGraph*&G,charvex[],intn,etypeedge[],inte)

查找结点在十字链表中的位置:

intLocateVex(ALGraph*G,Vertexu)

插入指定边:

boolInsertArc(ALGraph*G,etypea)

删除指定边:

boolDeletetArc(ALGraph*G,etypea)

查找有向图中指定结点的度(出度和入度):

intCount(ALGraph*G,Vertexu)

数据类型

/*边的数据类型*/

typedefstruct

{charvi,vj;

intinfo;

}etype;

/*弧结点数据类型*/

typedefstructArcNode

{inttailvex,headvex;/*该弧的尾和头顶点的位置*/

structArcNode*hlink,*tlink;/*分别为弧头相同和弧尾相同的弧的链域*/

InfoTypeinfo;/*若为网络则为权值*/

}ArcNode;

/*表头结点数据类型*/

typedefstructVexNode

{Vertexdata;

ArcNode*firstin,*firstout;/*指向该顶点的第一条入弧和出弧*/

}VexNode;

typedefVexNodeAdjList[MAXV];

/*十字链表数据类型*/

typedefstruct

{AdjListadjlist;

intn,e;/*图中顶点数n和边数e*/

}ALGraph;

概要设计

CreateDG(建表)

(1)获取有向图的顶点数、弧数并存入;

(2)依次获取各顶点的值,存入数组,构建十字链表头结点向量组;

(3)依次获取弧信息,存入,确认弧结点在十字链表中的位置并对弧赋值;

(4)十字链表创建成功;

LocateVex(查找)

传参:

有向图,顶点

利用指针依次扫描表头数组,当找到该顶点时,返回该顶点在十字链表表头数组的位置(序号),未找到该顶点时,返回-1。

Count(求度)

传参:

有向图,顶点

调用LocateVex(),找到顶点的位置,利用tlink指针依次扫描以该顶点为弧尾的边,统计该顶点的出度,利用hlink指针依次扫描以该顶点为弧头的边,统计该顶点的入度,那么该顶点的度为入度加出度。

InsertArc(插入边)

传参:

有向图,边

调用LocateVex(),找到顶点的位置,建立新的存储空间,对新存储空间赋值,通过修改tlink和hlink,将新结点放入十字链表。

boolDeletetArc(ALGraph*G,etypea)

传参:

有向图,边

调用LocateVex(),找到顶点的位置,通过修改指针,将指定的边结点从十字链表中删除,同时释放存储空间。

详细设计(源代码)

/*建立十字链表*/

voidcreat_crosslink(ALGraph*&G,charvex[],intn,etypeedge[],inte)

{ArcNode*p;

G=(ALGraph*)malloc(sizeof(ALGraph));

G->n=n;G->e=e;

intk,i,j;

for(i=0;i

{

G->adjlist[i].firstin=NULL;

G->adjlist[i].firstout=NULL;

G->adjlist[i].data=vex[i];

}

for(k=0;k

{i=0;

while(G->adjlist[i].data!

=edge[k].vi)

i++;

j=0;

while(G->adjlist[j].data!

=edge[k].vj)

j++;

p=(ArcNode*)malloc(sizeof(ArcNode));

p->headvex=i+1;//始边顶点(数组元素第一个序号为0)

p->tailvex=j+1;//终边顶点

p->info=edge[k].info;//权值

p->hlink=G->adjlist[i].firstout;//建立弧头链表

p->tlink=G->adjlist[j].firstin;//建立弧尾链表

G->adjlist[i].firstout=G->adjlist[j].firstin=p;//头插

}

}

/*查找指定顶点的位置(序号)*/

intLocateVex(ALGraph*G,Vertexu)

{inti;

for(i=0;i<(*G).n;i++)//循环查找结点

if((*G).adjlist[i].data==u)

returni;//如果找到该结点就返回其在十字链表中的序号

return-1;//如果没有找到该结点,返回-1

}

/*求指定顶点的度*/

intCount(ALGraph*G,Vertexu)

{inti=0,j=0,k;

ArcNode*p,*q;

k=LocateVex(G,u);//k是顶点v的序号

if(k<0)//k不是图G的顶点

return-1;

p=(*G).adjlist[k].firstin;//找出弧

q=(*G).adjlist[k].firstout;//找入弧

while(p!

=NULL&&p->tlink!

=NULL)//依次扫描以该顶点为尾结点的弧

{p=p->tlink;

i++;

}

while(q!

=NULL&&q->hlink==NULL)//依次扫描以该顶点为头结点的弧

{q=q->hlink;

j++;

}

returni+j;

}

/*插入新边*/

boolInsertArc(ALGraph*G,etypea)

{inti,j;

ArcNode*p;

i=LocateVex(G,a.vi);//弧尾序号

j=LocateVex(G,a.vj);//弧头序号

if(i<0||j<0)

returnfalse;

p=(ArcNode*)malloc(sizeof(etype));//生成新结点

p->tailvex=i;//给新结点赋值

p->headvex=j;

p->info=a.info;

p->hlink=(*G).adjlist[j].firstin;//插在入弧和出弧的链头

p->hlink=(*G).adjlist[i].firstout;

(*G).adjlist[j].firstin=(*G).adjlist[i].firstout=p;

(*G).e++;//弧数+1

returntrue;

}

/*删除指定边*/

boolDeletetArc(ALGraph*G,etypea)

{inti,j;

ArcNode*p1,*p2;

i=LocateVex(G,a.vi);//弧尾序号

j=LocateVex(G,a.vj);//弧头序号

if(i<0||j<0||i==j)

returnfalse;

p2=(*G).adjlist[i].firstout;//将弧结点从出弧表中删去

if(p2&&p2->headvex==j)//第一个结点为待删除结点

(*G).adjlist[i].firstout=p2->tlink;

else

{while(p2&&p2->headvex!

=j)

{p1=p2;

p2=p2->tlink;

}

if(p2)//没到表尾

p1->tlink=p2->tlink;

}

p2=(*G).adjlist[j].firstin;//将弧结点从入弧链表中删去

if(p2&&p2->tailvex==i)

(*G).adjlist[j].firstin=p2->hlink;

else

{while(p2&&p2->tailvex!

=i)

{p1=p2;

p2=p2->hlink;

}

if(p2)//没到表尾

p1->hlink=p2->hlink;

}

if(p2->info)//释放弧结点

free(p2);

(*G).e--;//弧数-1

returntrue;

}

调试分析及问题解决

1、typedefstructOLGArc,定义弧结点结构体,包含:

两个整数类型的数据:

tailvex、headve,q,分别为该弧的尾顶点、头顶点和该弧的权值;两个指针:

*hlink、*tlink,分别为与该弧拥有相同头顶点的链域和与该弧拥有相同尾顶点的链域;

2、typedefstructOLGVNode,定义顶点结点结构体,包含:

一个字符类型的数据:

data,为顶点的名字;两个指针:

*firstin,*firstout,分别指向该顶点的第一条入弧和出弧;

3、typedefstructALGraph,定义十字链表结构体,包含:

一个OLGVNode类型的数组,用于存放表头向量;两个整数类型的数据:

vexnum、arcnum,分别为有向图的当前顶点数和弧数;

4、StatusCreateDG(ALGraph*G),创建十字链表的函数,实现创建空的十字链表,在十字链表中放入有向图的顶点、弧、权值等功能;

5、voidDestroyGraph(ALGraph*G),销毁十字链表的函数,实现销毁用十字链表存储的有向图的功能;

6、VertexType*GetVex(ALGraphG,intv),查找序号为v的顶点并返回该顶点的名字(即该顶点的值);

7、建表时为了统一代码,由另一人更改了建表的操作,导致建表时从1开始计数而不是0,后面的查找和删除功能有误;更改后正常。

8、在插入指定边时,插入边将原有的边覆盖;在查找指定结点的度时,获得的结果不正确,特别是在插入一条新边后的数据与原数据的差不为1。

解决办法:

通过调试查找,找到了错误来源:

1、在创建十字链表时,数据的下标是从1开始存储的,而在“查找指定结点的度”、“插入边”、“删除边”等函数中均默认十字链表的存储下标是从0开始;2、在创建十字链表时,出现弧头和弧尾的定义与函数中的定义相反(如下图说明)。

于是进行如下修改:

1、将创建十字链表函数中的下标改为从0开始存储;2、将“查找指定结点的度”、“插入边”、“删除边”等函数出现的弧头相关信息改为弧尾的,将弧尾相关信息改为弧头的。

再次经过调试,证明程序正确。

关键路径

功能概述

输入有向图,求其关键路径及最短时间。

模块简介

创建有向图邻接表;creatlink(ALGraph*&G,charvex[],intn,etypeedge[],inte)

输入有向图邻接表;Inputgraph(ALGraph*&G)

获取事件发生最早时间;intget_ve(ALGraph*G,inti,VNodeq)

获取时间发生最迟时间;intget_vl(ALGraph*G,inti,VNodeq)

对有向图进行拓扑排序;TopSort(ALGraph*&G)

求关键活动及最短时间。

get_keyroad(ALGraph*G)

数据类型

/*边的数据类型*/

typedefstruct

{charvi,vj;

intinfo;

}etype;

/*边结点数据类型*/

typedefstructANode

{intadjvex;/*邻接点存储序号*/

intlt;/*活动最迟发生时间*/

intflag;/*标记是否为关键活动*/

InfoTypeinfo;/*若是网络存储权值*/

structANode*nextarc;/*指向下一个边结点*/

}ArcNode;

/*表头结点数据类型*/

typedefstruct

{Vertexdata;/*存储顶点元素*/

intcount;/*顶点入度*/

intve,vl;/*事件最早及最迟发生时间*/

ArcNode*firstarc;/*指向依附于该顶点的第一边*/

}VNode;

typedefVNodeAdjList[MAXV];

/*邻接表数据类型*/

typedefstruct

{AdjListadjlist;

intn,e;/*图中顶点数n和边数e*/

}ALGraph;

概要设计

Creatlink(建表)此函数用于调试后面的功能

传参:

空表,顶点,顶点个数,边数,有向边信息

邻接表为链式存储,传参使用的数组则为顺序存储。

步骤为:

1.将顶点信息(charvex[])放入表头结点(G->adjlist[i].data);2.将有向边信息(etypeedge[])填入表中作为边结点。

为了方便调试采用尾插法,后期可能会改成头插。

Inputgraph(输入图)此函数为正式建表

传参:

空的有向图

步骤为:

先输入顶点数和边数,确定邻接表大小后再进行边信息的录入。

输入顶点信息,建立邻接表头->输入边信息,将边信息填入表中作为边结点。

为了便于调试采用尾插法。

TopSort(拓扑排序)

传参:

有向图(以邻接表方式存储)

步骤为:

利用栈存储入度为零的顶点,逐一输出,再删去其作为始点出发的边得出下一个入度为零的点,输出,重复上述步骤,即得拓扑排序序列。

一边进行拓扑排序的同时一边调用get_ve(图,头结点序号,头结点)函数获得每个事件发生的最早时间,同时将序列存入一个栈St1以便后面获得拓扑排序逆序列。

由于St1属于本函数中的局部变量,因此get_vl函数放在本函数里,对St1进行出栈操作,获取拓扑排序逆序列并求算事件最迟发生时间。

get_keyroad(关键路径及最短时间)

传参:

有向图(以邻接表方式存储)

遍历有向图,利用公式

活动最迟发生时间=终点事件最迟发生时间-活动持续时间

活动最早发生时间=起点事件最早发生时间

求出关键活动,以此获得关键路径及最短时间。

详细设计(源代码)

/*建立邻接表*/

voidcreatlink(ALGraph*&G,charvex[],intn,etypeedge[],inte)

{ArcNode*p,*t;

t=(ArcNode*)malloc(sizeof(ArcNode));

t->nextarc=NULL;

G=(ALGraph*)malloc(sizeof(ALGraph));

G->n=n;G->e=e;

intk,i,j;

for(i=0;i

{

G->adjlist[i].firstarc=NULL;

G->adjlist[i].data=vex[i];

G->adjlist[i].ve=0;

}

for(k=0;k

{i=0;

while(G->adjlist[i].data!

=edge[k].vi)

i++;

j=0;

while(G->adjlist[j].data!

=edge[k].vj)

j++;

p=(ArcNode*)malloc(sizeof(ArcNode));

p->adjvex=j;//终边顶点

p->info=edge[k].info;//权值

p->flag=0;//默认为非关键活动

if(G->adjlist[i].firstarc==NULL)//尾插

{G->adjlist[i].firstarc=p;

p->nextarc=NULL;

t=p;

}

else

{t->nextarc=p;

p->nextarc=NULL;

t=p;

}

}

}

/*输入邻接表*/

voidInputgraph(ALGraph*&G)

{chare[2];

intl,i,j,k=0;//l:

边长

ArcNode*p,*t;

t=(ArcNode*)malloc(sizeof(ArcNode));

t->nextarc=NULL;

G=(ALGraph*)malloc(sizeof(ALGraph));

printf("pleaseinputvexandedgenumber:

\n");//先输入顶点数和边数

scanf("%d%d",&G->n,&G->e);

for(i=0;in;i++)/*置入各表头结点(即顶点)*/

{

G->adjlist[i].data='a'+i;//自动生成顶点

G->adjlist[i].firstarc=NULL;

G->adjlist[i].ve=0;

}

while(ke)//输入边信息

{printf("pleaseaddedgeinformation:

\n");

scanf("%s",e);

scanf("%d",&l);

i=0;

while(G->adjlist[i].data!

=e[0])

i++;

j=0;

while(G->adjlist[j].data!

=e[1])

j++;

p=(ArcNode*)malloc(sizeof(ArcNode));

p->adjvex=j;//终边顶点

p->info=l;//权值

p->flag=0;//默认为非关键活动

if(G->adjlist[i].firstarc==NULL)//尾插

{G->adjlist[i].firstarc=p;

p->nextarc=NULL;

t=p;

}

else

{t->nextarc=p;

p->nextarc=NULL;

t=p;

}

k++;

}

}

/*获取事件发生最早时间*/

intget_ve(ALGraph*G,inti,VNodeq)

{intj=0;

ArcNode*p;

if(i==0)return0;

else

{while(j

{p=G->adjlist[j].firstarc;

if(p==NULL)

{j++;

continue;

}

while(p->nextarc!

=NULL&&p->adjvex!

=i)

p=p->nextarc;

if(p->adjvex==i&&

p->info+G->adjlist[j].ve>=G->adjlist[i].ve)

{G->adjlist[i].ve=p->info+G->adjlist[j].ve;

j++;

}

elsej++;

}

returnG->adjlist[i].ve;

}

}

/*获取事件发生最迟时间*/

intget_vl(ALGraph*G,inti,VNodeq)

{ArcNode*p;

p=G->adjlist[i].firstarc;

if(i==0)return0;

G->adjlist[i].vl=G->adjlist[p->adjvex].vl-p->info;//出度为0的顶点只有一个且已出栈,此处无需判断p!

=NULL

while(p->nextarc!

=NULL)

{p=p->nextarc;

if(G->adjlist[i].vl>=G->adjlist[p->adjvex].vl-p->info)

G->adjlist[i].vl=G->adjlist[p->adjvex].vl-p->info;

}

returnG->adjlist[i].vl;

}

/*拓扑排序*/

voidTopSort(ALGraph*G)

{inti,j;

intSt[MAXV],top=-1;

ArcNode*p;

for(i=0;in;i++)/*入度置为0*/

G->adjlist[i].count=0;

for(i=0;in;i++)/*求所有顶点的入度*/

{p=G->adjlist[i].firstarc;

while(p!

=NULL)

{G->adjlist[p->adjvex].count++;//终点入度+1

p=p->nextarc;

}

}

for(i=0;in;i++)/*入度为0的顶点进栈*/

if(G->adjlist[i].count==0)

{top++;

St[top]=i;

}

/*进行拓扑排序并将结果逐个输出*/

while(top>-1)//栈不为空时进行循环

{i=St[top];top--;

printf("%c",G->adjlist[i]);

p=G->adjlist[i].firstarc;

while(p!

=NULL)

{j=p->adjvex;

G->adjlist[j].count--;

if(G->adjlist[j].count==0)

{top++;

St[top]=j;

}

p=p->nextarc;

}

}

}

/*关键路径及最短时间*/

voidget_keyroad(ALGraph*G)

{inti=0,stime=0;

ArcNode*p;

printf("%c",G->adjlist[i]);

while(in)

{p=G->adjlist[i].firstarc;

while(p!

=NULL)

{p->lt=G->adjlist[p->adjvex].vl-p->info;

if(p->lt-G->adjlist[i].ve==0)

{p->flag=

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1