关键路径问题c语言实习课程论文.docx
《关键路径问题c语言实习课程论文.docx》由会员分享,可在线阅读,更多相关《关键路径问题c语言实习课程论文.docx(13页珍藏版)》请在冰豆网上搜索。
关键路径问题c语言实习课程论文
西北农林科技大学信息工程学院
C语言和数据结构实习报告
题目:
关键路径问题
学号
姓名
专业班级
软件093
指导教师
实践日期
\
目录
一、综合训练目的与要求3
二、综合训练任务3
三、总体设计3
四、详细设计说明4
五、调试与测试7
六、实习日志10
七、实习总结12
八、附录:
核心代码清单12
一、综合训练目的与要求
本综合训练是计算机科学与技术、信息管理与信息系统、软件工程专业重要的实践性环节之一,是在学生学习完《程序设计语言(C)》、《数据结构》课程后进行的一次全面的综合练习。
本课综合训练的目的和任务:
1.巩固和加深学生对C语言、数据结构课程的基本知识的理解和掌握;
2.掌握C语言编程和程序调试的基本技能;
3.利用C语言进行基本的软件设计;
4.掌握书写程序设计说明文档的能力;
5.提高运用C语言、数据结构解决实际问题的能力。
二、综合训练任务
基本要求:
(1)对一个描述工程的AOE网,建立其存储结构;(注:
数据的输入可以是键盘输入或文件输入两种方式)
(2)判断该AOE网是否能够顺利进行。
(3)若该工程能顺利进行,输出完成整项工程至少需要多少时间,以及每一个关键活动所依附的两个顶点、最早发生时间、最迟发生时间。
(注:
结果的输出可以是屏幕输出和文件输出两种方式)
三、总体设计
主流程图
四、详细设计说明
对于问题的分析:
由于在AOE-网中有些活动可以并行进行,所以完成工程的最短时间就是从开始点到完成点的最长路径的长度,所以路径长度最长的路径叫做关键路径。
求关键路径的算法:
(1)输入e条弧,建立AOE-网的存储结构;
(2)从源点V0出发,令Ve[0]=0,按拓扑有序求其余各定点的最早发生时间Ve[i](1<=i<=n-1)。
如果得到的拓扑有序序列中的顶点个数小于网中顶点数n,则说明网中存在环,不能求关键路径,算法终止;否则执行步骤(3)。
(3)从汇点Vn出发,令Vl[n-1]=Ve[n-1],按拓扑有序求其余各顶点的最迟发生时间Vl[i](n-2>=i>=2);
(4)根据各顶点的Ve和Vl值,求每条弧s的最早开始时间e(s)和最迟开始时间l(s).。
若某条弧满足条件e(s)=l(s),则为关键活动。
如上所述,计算各顶点的Ve值是在拓扑排序的过程中进行的,需要对拓扑排序的算法作如下修改:
(a)在拓扑排序之前设初值,令Ve[i]=0(0<=i<=n-1);
(b)在算法中增加一个计算Vj的直接后继Vk的最早发生时间的操作:
若Ve[j]+dut()>Ve[k],则Ve[k]=Ve[j]+dut();
(c)为了能按逆拓扑有序序列的顺序计算各顶点的Vl值,需要记下在拓扑排序的过程中求得的拓扑有序序列,这需要在拓扑排序算法中,增设一个栈以记录拓扑有序序列,则在计算机求得各顶点的Ve值以后,从栈顶至栈底便为逆拓扑有序序列。
在程序末端要对程序进行改进,使其输入具有键盘输入和文件输入两种方式,输出也具有键盘输出和文件输出两种方式。
本程序所需要的结构体及宏定义如下:
#defineOK1
#defineINFEASIBLE-1
#defineOVERFLOW-2
#defineMAX_VERTEX_NUM20//最大顶点个数图的
#defineSTACK_INIT_ZSIZE100//存储空间初始分配量栈的
#defineSTACKINCREMENT10//存储空间分配增量栈的
typedefintStatus;//类型
typedefintSElemType;
typedefintVertexType;
typedefintInfoType;
//--------------------栈结构-------------------
typedefstruct
{
SElemType*base;//在栈构造之前和销毁之后,base的值为NULL
SElemType*top;//栈顶元素
intstacksize;//当前已分配的存储空间,以元素为单位
}SqStack,*Stack;
//--------------------图结构-------------------
typedefstructArcNode//表结点
{
intadjvex;//该弧所指向的顶点的位置
structArcNode*nextarc;//指向下一条弧的指针
intinfo;//该弧的相关信息的指针
}ArcNode;
typedefstructVNode//头结点
{
VertexTypedata;//顶点信息
ArcNode*firstarc;//指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM];
typedefstruct//图信息
{
AdjListvertices;
intvexnum,arcnum;//图的当前顶点数和弧数
intInclnfo;
intkind;//图的种类标志
}ALGraph;
主要功能函数为:
StatusInitStack(StackS);//构造一个空栈S
StatusPush(StackS,SElemTypee);//入栈
StatusPop(StackS,SElemType*e);//出栈
上述三个函数则在实现拓扑排序以及关键路径的算法中需要用到。
voidFindInDegree(ALGraphG,int*indegree);//求顶点的入度
求顶点的入度函数则是在拓扑排序中用到,配合栈的函数。
intLocateVex(ALGraphG,intu);//返回顶点v在图顶点向量中的位置
返回顶点的位置,则运用在构造邻接表的函数中。
voidCreateADG(ALGraph*G);
键盘输入-建立邻接表
intFileCreateADG(charsourceFileName[],ALGraph*G);
文件输入-建立邻接表
voidFilePrint(ALGraphG);
文件输出邻接表
voidPrint(ALGraphG);
屏幕打印邻接表
StatusTopologicalOrder(ALGraphG,StackT);
拓扑排序
StatusFileCriticalPath(ALGraphG);
文件输出关键路径
StatusCriticalPath(ALGraphG);
屏幕打印关键路径
intDrawPrint();
屏幕开始欢迎介绍
voidPrintG2File(ALGraphG);
判断是否文件输入
voidPrintfG2Screen(ALGraphG);
判断是否文件输入
intselet();
整体算法排序
intselet2();
结束画面函数五、调试与测试
下面先进行对于问题的人工测试:
【例一】下面是分析所得:
图7.21是一个网。
其中有9个事件v1,v2,…,v9;11项活动a1,a2,…,a11。
每个事件表示在它之前的活动已经完成,在它之后的活动可以开始。
如v1表示整个工程开始,v9表示整个工程结束。
V5表示活动a4和a5已经完成,活动a7和a8可以开始。
与每个活动相联系的权表示完成该活动所需的时间。
如活动a1需要6天时间可以完成。
(1)AOV网具有的性质
⒈只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始。
⒉只有在进入某一顶点的各有向边所代表的活动都已经结束,该顶点所代表的事件才能发生。
⒊表示实际工程计划的AOE网应该是无环的,并且存在唯一的入度过为0的开始顶点和唯一的出度为0的完成顶点。
(2)由事件vj的最早发生时间和最晚发生时间的定义,可以采取如下步骤求得关键活动:
1.从开始顶点v1出发,令ve
(1)=0,按拓朴有序序列求其余各顶点的可能最早发生时间。
Ve(k)=max{ve(j)+dut()}(7.1)
j∈T
其中T是以顶点vk为尾的所有弧的头顶点的集合(2≤k≤n)。
如果得到的拓朴有序序列中顶点的个数小于网中顶点个数n,则说明网中有环,不能求出关键路径,算法结束。
2.从完成顶点vn出发,令vl(n)=ve(n),按逆拓朴有序求其余各顶点的允许的最晚发生时间:
vl(j)=min{vl(k)-dut()}
k∈S
其中S是以顶点vj是头的所有弧的尾顶点集合(1≤j≤n-1)。
3.求每一项活动ai(1≤i≤m)的最早开始时间e(i)=ve(j);最晚开始时间
l(i)=vl(k)-dut()
。
若某条弧满足e(i)=l(i),则它是关键活动。
对于图7.21所示的AOE网,按以上步骤的计算结果见表7.3,可得到a1,a4,a7,a8,a10,a11是关键活动。
(3)求出AOE网中所有关键活动后,只要删去AOE网中所有的非关键活动,即可得到AOE网的关键路径。
这时从开始顶点到达完成顶点的所有路径都是关键路径。
一个AOE网的关键路径可以不止一条,如图7.21的AOE网中有二条关键路径,(v1,v2,v5,v7,v9)和(v1,v2,v5,v8,v9)它们的路径长度都是16。
如图7.24所示。
下面有程序所得的结果:
关键活动为:
从1到2的关键路径是6,发生时间为:
0
从2到5的关键路径是1,发生时间为:
6
从5到8的关键路径是7,发生时间为:
7
从5到7的关键路径是9,发生时间为:
7
从7到9的关键路径是2,发生时间为:
16
从8到9的关键路径是4,发生时间为:
14
其中分析所得与程序所得相同。
下面简单再多列举几个例子进行调试与测验:
【例二】
顶点数:
5
边数:
6
第一条边的信息:
由1—>2,权值为2
第二条边的信息:
由1—>3,权值为3
第三条边的信息:
由1—>4,权值为4
第四条边的信息:
由2—>3,权值为2
第五条边的信息:
由3—>5,权值为5
第六条边的信息:
由4—>5,权值为6
分析所得关键路径为:
1—>4—>5,时间长度为10;
由程序所得:
关键活动为:
从1到4的关键路径是4,发生时间为:
0
从4到5的关键路径是6,发生时间为:
4
分析与程序所得相同。
【例三】
顶点数:
8
边数:
9
第一条边的信息:
由1—>2,权值为3
第二条边的信息:
由1—>3,权值为5
第三条边的信息:
由2—>6,权值为7
第四条边的信息:
由6—>7,权值为5
第五条边的信息:
由5—>7,权值为8
第六条边的信息:
由3—>5,权值为4
第七条边的信息:
由3—>4,权值为6
第八条边的信息:
由4—>8,权值为9
第九条边的信息:
由7—>8,权值为6
分析所得关键路径为:
1—>3—>5—>7—>8,时间长度为23;
由程序所得:
关键活动为
从1到3的关键路径是5,发生时间为:
0
从3到5的关键路径是4,发生时间为:
5
从5到7的关键路径是8,发生时间为:
9
从7到8的关键路径是6,发生时间为:
17
分析与程序所得相同。
六、实习日志
【第一天】
拿到的题目是求做一个工程的关键路径,此题目是数据结构书上的一个算法,所以在简单的在vc6++里面将一些基本以后要用到的头文件、宏定义、各结构体等先建立好,然后根据题目的要求开始看书,整体想此题的思路是什么?
如何开始去做,以及做的每一步骤是什么?
求关键路径要用到栈的知识、所以在今天先编写了进栈和出栈的函数,以便今后拓扑排序函数和求关键路径函数的使用,也初步学习了如何用邻接表构造一个有向图。
【第二天】
继续昨天还未完成的函数——用邻接表构造一个有向图。
看书以及在网上找了一些代码先明白了如何用邻接表构造一个有向图的算法,先输入顶点值,也就是头结点,这是一个数组,再输入边的值,这是每个头结点引出的一个链式结构,在构造图时,还要编写判断输入非法或者错误的语句,使得程序健硕性。
之后进行拓扑排序的程序算法,要用到判断顶点入度的函数,也要用到判栈空的函数,所以在前面的函数上先将这两个函数补上去。
然后开始对拓扑排序函数就行研究。
【第三天】
今日对拓扑函数进行了研究和学习,在明白了其排序原理后,将书上的伪代码进行了研读,以及如何可以将伪代码写成可执行的函数,其中要用到之前准备好的栈结构,而在写完代码后,运行的结果总是有问题,例如:
errorC2115:
'function':
incompatibletypes和warningC4024:
'InitStack':
differenttypesforformalandactualparameter1等问题,在经过开始自己的摸索与后来问老师的回答,我补充自己在C语言方面的漏洞,在函数调用的时候,我们不仅要靠调用的参数,还要考虑是实参还是形参,以及调用结束后是否需要返回值改变等等问题。
在解决了传值问题之后开始解决拓扑排序问题,也对其中要用到的函数进行了编写,例如LocateVex(返回顶点v在图顶点向量中的位置)函数的编写。
【第四天】
通过昨天对拓扑函数的编写,今天的任务主要是关键路径的编写,也是这个程序的最后一个函数。
通过看书上的伪代码,写对其进行算法进行了了解,再将其改为可执行的C语言代码,关键路径要用到昨天编写的拓扑排序,通过拓扑排序算出各个顶点的最早发生时间,在顺便将其按拓扑排序放在一个栈里面,在关键路径的算法中则刚好用到已排好序的栈,可以算出最迟发生时间。
则最早发生时间与最迟发生时间相等则是关键路径。
通过将最后一个函数编写完,除了文件方面的知识,基本已经完成了雏形,并对其进行了调试。
【第五天】
相对已经初具模型的程序进行调试,发现了好多错误,以前都只是按右键点击
,在函数里设置断点,然后按F10来进行对程序的调试,而今天也学会了另一种方式的调试,用这个
图标在有问题的地方设置上断点,然后可以点击
这个图标对程序进行调试,也同时明白了这几个
图标的含义,{}表示函数,
:
跳到函数里面调试,
:
跳过当前函数,
:
跳出这个函数。
对程序进行了一些改正,开始着手文件方面的知识,由于当时学的时候几乎等于没有学,所以今天只是在看书,并将书上所写的文件函数代码输入到VisualC++6.0进行练习。
【第六天】
由于题目要求是文件输入和键盘输入两种方式,所以就对其进行文件输入的编写,文件读入有以下几种方式:
fgetc();是从指定的文件中读一个字符,fgets();从指定的文件中读一个字符串到字符数组中,fread();用于读出一组数据,返回已读出数据的个数,fscanf();其功能与键盘输入的scanf();功能差不多,只是对象是文件。
为了将文件中的数据读出并构建有向图的邻接表,所以用哪一个读出函数比较好,并且其函数有了,如何实现用读出的数据来建立有向图,开始想着用fgets();获得一行,然后用每行的数据去构建邻接表,但是对输入顶点和权值那一项却不知道如何进行,所以放弃了此种方法,最后选定为fscnaf();函数来输入数据,在和老师共同探讨之下,早上基本完成了其文件的输入问题。
下午,开始实行最后一个问题:
文件输出问题。
文件的输出也有好几个,比如fputc();fputs();fwrite();以及fprintf();对于输出,老师的方法让我大开眼见,也知道了fprintf();不仅仅在括号里必须输入三项,只要两项就好了,也就是说仅仅只要将曾经的键盘输出的printf();改成fprintf();且在里面加入文件指针就可以将其内容打印在文件中。
【第七天】
对程序进行整体的调试和测试,输入正确和错误的程序,看程序是否正确,如不正确则对其进行修改。
对程序的输出界面进行设计,如何简单大方得体,是客户看着舒心则是我的目的,也在周围看了下其他同学的输出界面,对其进行学习,学会了如何使输出界面的屏幕颜色进行更改,也顺便将自己的界面改成一个柔和的界面。
【第八天】
在做完整个界面的设计后,并输出格式的错误,使其界面依旧完整统一化。
对已经完工的程序看是否还有改进的地方,也通过输入错误的值,更加知道程序的一些漏洞,比如在输入错误的后,是否可以更具客户的要求而不退出系统,以及在选择了文件输入后是否还可以根据客户的要求打印在屏幕上,或者选择键盘输入后是否可以根据客户的要求在打印在文件里。
今天便是进行对程序漏洞的修改。
以及使程序更加人性化。
【第九天】
对程序的流程进行分析并画出流程图,也在观看了几名同学的成果展示之后,又对自己的程序进行了修改,为了更好的满足客户的要求,又添加了一项功能,在每次结果出来后,问下客户是否需要继续,是则继续进行程序,不是则退出。
也是看了几个同学的系统,自己也添加了清屏的功能。
并在下午开始写实习论文。
【第十天】
我们今天早上实习答辩。
由于昨天晚上突然想到文件输入构建图,如果文件数据是错误的,如何解决,并且在昨天晚上解决到两点仍无法解决,所以今天下午来问老师将代码作了进一步的改进。
七、实习总结
通过这次的实习,自己的编程能力有了一定的提升,不仅仅是对程序的编写能力,也是对程序各方面考虑的能力都有很大的提高。
我的题目是求关键路径,是这学期刚学到的新知识,要用图的结构来解决问题。
其中就有有向图的建立,以及拓扑排序,关键路径的算法。
题目还要求用到键盘输入和文件输入两种方式,所以则需要用到去年学的文件方面的知识,文件对于我们来说,还是一个盲点,所以通过这一次的实习,使我对于文件的掌握有了更一步加深。
在程序基本写好后,调试和测试则成了重点,以前很少用到调试,甚至也不太会,而通过这一次的实习,当遇到问题则会自己先通过调试解决,如果调试之后还解决不了了,则会向老师请教,而老师往往会给我们一些更好的以及更简单的方法去实现相应的功能。
在最后几天了,不仅仅是对算法实现以及编程提高了,还对于如何使函数更加健硕进行了深度思考,教会了我要对问题要全面分析,以及对于问题会出现的漏洞也要进行全面分析,并且将漏洞都补好。
这次的实习使我的思路变得更加的开阔,也使得编程能力得到了提高,感谢这一次的实习。
}