数据结构实验五教学计划编制.docx
- 文档编号:29501921
- 上传时间:2023-07-24
- 格式:DOCX
- 页数:24
- 大小:192.86KB
数据结构实验五教学计划编制.docx
《数据结构实验五教学计划编制.docx》由会员分享,可在线阅读,更多相关《数据结构实验五教学计划编制.docx(24页珍藏版)》请在冰豆网上搜索。
数据结构实验五教学计划编制
HUNANUNIVERSITY
实验五最终报告
题目教学计划编制问题
学生姓名
学生学号
专业班级
指导老师李晓鸿
完成日期2015年12月17日
一.需求分析
1.程序的功能
用户通过键盘输入课程总数、每门课的课程编号和直接先修的课程号等的参数。
用有向网表示教学计划,其中顶点表示某门课程,有向边表示课程之间的先修关系(如果A课程是B课程的先修课程,那么A到B之间有一条有向边从A指向B)。
最终输出一个不冲突的线性的课程教学流程。
2.输入形式
请输入课程总数:
//输入一个正整数n
请输入课程1的名称:
//输入任意字符串
请输入课程2的名称:
..............
请输入课程n的名称:
(课程1)否是有先修(1/0):
//输入1表示有,0表示没有
若输入1:
请输入先修课程的名称:
//输入存在的先修课程名称
...............
(课程n)否是有先修(1/0):
请输入先修课程的名称:
3.输出形式
输出成功:
课程表的排序为:
//输出没有冲突的课表排序
输出失败:
课程输入错误!
教学计划编制失败,请重新输入。
4.测试数据:
①.正常的输入
输入:
输入课程总数:
3
请输入课程1的名称:
小学数学
请输入课程2的名称:
初中数学
请输入课程3的名称:
大学数学
小学数学是否有先修(1/0):
0
初中数学是否有先修(1/0):
1
请输入先修课程的名称:
小学数学
高中数学是否有先修(1/0):
1
请输入先修课程的名称:
初中数学
输出:
课程表的排序为:
小学数学初中数学高中数学
②.正常的输入
输入:
输入课程总数:
4
请输入课程1的名称:
1
请输入课程2的名称:
2
请输入课程3的名称:
3
请输入课程4的名称:
4
1是否有先修(1/0):
0
请输入先修课程的名称:
4
2是否有先修(1/0):
1
请输入先修课程的名称:
3
3是否有先修(1/0):
1
请输入先修课程的名称:
4
4是否有先修(1/0):
0
输出:
课程表的排序为:
4132
③.有两个先修课程的情况
输入:
输入课程总数:
4
请输入课程1的名称:
A
请输入课程2的名称:
B
请输入课程3的名称:
C
请输入课程4的名称:
D
A是否有先修(1/0):
0
B是否有先修(1/0):
1
请输入先修课程的名称:
A
C是否有先修(1/0):
1
请输入先修课程的名称:
A
D是否有先修(1/0):
1
请输入先修课程的名称:
C
输出:
课程表的排序为:
ABCD
④.有三个先修课程的情况
输入:
输入课程总数:
4
请输入课程1的名称:
A
请输入课程2的名称:
B
请输入课程3的名称:
C
请输入课程4的名称:
D
A是否有先修(1/0):
1
请输入先修课程的名称:
D
B是否有先修(1/0):
1
请输入先修课程的名称:
D
C是否有先修(1/0):
1
请输入先修课程的名称:
D
D是否有先修(1/0):
0
输出:
课程表的排序为:
DABC
⑤.所有课程无先修
输入:
输入课程总数:
3
请输入课程1的名称:
1
请输入课程2的名称:
2
请输入课程3的名称:
3
A是否有先修(1/0):
0
B是否有先修(1/0):
0
C是否有先修(1/0):
0
输出:
课程表的排序为:
123
二、概要设计
1.抽象数据类型
题设要求使用一个有向图表示教学计划,顶点表示某门课程,有向边表示课程之间的先修关系,数据的对象是图中的每一个顶点和有向边。
由此为本问题确定一个图的数据关系。
本题目需要一个数据结构来储存遍历过的图的结点,该数据结构满足先进先出,所以用队列来实现。
2.ADT
ADTEdge{
数据对象:
N(边的名称)V(标记)F(先修课结点)
数据关系:
(N&&V&&F)∈R
(R1&&R2&&Rn)∈Graph
基本操作:
stringgetVal(intv)//返回边的名称
intgetMark(intv)//返回标记
voidsetVal(intv,stringval)//设边的名称
voidsetMark(intv,intMark)//设置标记
voidsetfirst(intv)//设置先修结点标记
}
ADTGraph{
数据对象:
V,R(分别代表某门课程的顶点组成的一个顶点集 V 和代表课程先修关系的有向弧边组成的一个弧集 R。
)
数据关系:
VR={
基本操作:
intn();//返回图中的顶点数
intfirst(int);//返回该点的第一条邻边
intnext(int);//返回该店的下一条邻边
voidsetEdge(int,int,int);//为有向边设置权值
voidFind(stringsearch,int&v)
intn()
}
ADTqueue{
数据对象:
前指针front,后指针rear
数据关系:
R={
约定a1为队列头,an为队列尾。
基本操作:
queue();//队列结构初始化
~queue();//结构销毁操作
boolpush(constint&it);//数据入列
boolpop(int&it);//数据出列
intsize();//获取队列长度}
3.算法的基本思想
①.通过用户输入的顶点的个数(课程数)初始化一个表示有向图的相邻矩阵,初始化边的访问次数全部设置为零,通过输入边的信息和先修关系,设置先修关系的计数器,记录每条边先修关系的数量,完成对有项图的构建。
②.将先修关系为零的边放入队列,然后开始处理队列。
当从队列中删除一个顶点时,把它打印出来,同时将其所有相邻顶点的先修关系计数器减一。
当某个相邻顶点的计数器为0时,就将其放入队列。
如果还有顶点未被打印,而队列已经为空,则图中必然包含回路(既不可能不违反先决条件完成任务)。
4.程序的流程
(1)初始化模块:
输入课程总数,再输入相应数量的课程编号及每个课程的先修课程,用这些信息初始化一个有向图。
(2)拓扑排序模块:
对有向图进行拓扑排序。
(3)输出模块:
根据有向图是否为空输出。
为空时,输出拓扑排序结果;不为空时输出输入错误提示。
三、详细设计
1.物理数据类型
用户输入的课程个数不定,所以存储拓扑排序后的顶点的个数不定,对于图有两种存储方式,本题中用邻接矩阵来存储图的信息,对于边很少的图来说,虽然用邻接矩阵有些浪费空间,但是题目做起来相对方便。
由于用户输入的课程个数不定,使用链式栈。
使用string类型储存用户信息和边的信息。
2.算法的具体步骤
初始化一个有向图——先修信息的储存——拓扑排序与输出
①.初始化一个有向图:
包括初始化被访问标记和先修标记,动态创建二维数组和用于储存边信息的一维数组。
Graph(intnumVert)
{
inti,j;
numVertex=numVert;
numEdge=0;
mark=newPoint[numVert];//Initializemarkarray
for(i=0;i { mark[i].visit=-1;//包括初始化被访问标记和先修标记 mark[i].first=0; } matrix=(int**)newint*[numVertex];//Makematrix for(i=0;i matrix[i]=newint[numVertex]; for(i=0;i for(intj=0;j } ②.先修信息的存储: 由用户输入是否有先修课程后,用户每输入一个先修课程,就将这个课程对应的先修标记加1. cout< cin>>judge; if(judge) { a.setfirst(i); cout<<"请输入先修课程的名称: "; cin>>Ch1; a.Find(Ch1,v1); a.setEdge(v1,i,10); } voidsetfirst(intv) { mark[v].first++; } ③.拓扑排序与输出: 定义两个队列A和B,将先修关系为零的边放入队列A,然后开始处理队列。 当从队列A中删除一个顶点时,该顶点进入B队列,再把该顶点打印出来,同时将其所有相邻顶点的先修关系计数器减一。 当某个相邻顶点的计数器为0时,就将其放入队列。 如果还有顶点未被打印,而队列已经为空,则图中必然包含回路(既不可能不违反先决条件完成任务)。 输出: 重复将队列B中首元素输出并删除,直到队列为空,就是课程表的排序。 voidDFS(Graph*G,queue { for(intv=0;v if(mark[v].first==0) { Q->push(v); setMark(v,1); } while(Q->size()! =0) { inti=Q->front();//获取Q栈首元素 Q->pop();//弹出Q栈 L->push(i);//进L栈 for(intw=first(i);w { mark[w].first--; if(mark[w].first==0) { Q->push(w);setMark(w,1); } } } for(inti=0;i { if(getMark(i)==-1)//为0时表示还未被删除,图不为空 { cout<<"课程输入错误! 教学计划编制失败,请重新输入。 "< exit(0); } } } 3.算法的时空分析及改进设想 因为图的邻接矩阵是一个|V|×|V|矩阵,所以邻接矩阵的空间代价为Θ(|V|^2),对于有n个顶点的和E条弧的有向图而言,对此图的拓扑排序算法时间复杂度为Θ(V+E) 4.输入和输出的格式 输入: 1.输入课程数n cout<<"请输入课程总数: "; cin>>n; if(n<=0) { cout<<"输入错误重新输入(大于零的整数)"< cout<<"请输入课程总数: "; cin>>n; } 2.输入每门课的课程编号 for(inti=0;i { cout<<"请输入课程"< "; cin>>Ch; a.setVal(i,Ch); } 3.获得先修的课程编号 for(inti=0;i { judge=0; cout< cin>>judge; if(judge) { a.setfirst(i); cout<<"请输入先修课程的名称: "; cin>>Ch1; a.Find(Ch1,v1); a.setEdge(v1,i,10); } } 输出: 1.编制成功,把队列S中的顶点序列输出。 cout<<"课程表的排序为: "< a.DFS(&a,&Q,&L); for(inti=0;i { intj=L.front(); cout< L.pop(); } 2.编制失败,图中有回路,输出错误信息,结束程序。 if(G.getMark(i)==0)//为0时表示该顶点未经过拓扑排序 { cout<<"课程输入错误! 教学计划编制失败,请重新输入。 "< exit(0); } 四.调试分析 DFS问题,书上思路很明确并且有很多源码,没有大的问题。 五.测试结果 1.正常的输入输出 ②.正常的输入 3.有两个先修课程的情况 ④.有三个先修课程的情况 ⑤.所有课程无先修 附录 #include #include #include #include #include usingnamespacestd; classPoint { public: stringLessonName; intvisit; intfirst;//1有先修,0无 }; classGraph {//Implementadjacencymatrix private: intnumVertex,numEdge;//Storenumberofverticesedges int**matrix;//Pointertoadjacencymatrix Point*mark;//Pointertomarkarray public: Graph(intnumVert) {//Makegraphw/numVertvertices inti,j; numVertex=numVert; numEdge=0; mark=newPoint[numVert];//Initializemarkarray for(i=0;i { mark[i].visit=-1; mark[i].first=0; } matrix=(int**)newint*[numVertex];//Makematrix for(i=0;i matrix[i]=newint[numVertex]; for(i=0;i for(intj=0;j } ~Graph() { delete[]mark; for(inti=0;i delete[]matrix[i]; delete[]matrix; } intn() { returnnumVertex; } inte() { returnnumEdge; } intfirst(intv) {//Returnv'sfirstneighbor inti; for(i=0;i if(matrix[v][i]! =0&&mark[i].visit==-1)returni; returni;//Returnnifnone } intnext(intv1,intv2) { //Getv1'sneighborafterv2 inti; for(i=v2+1;i if(matrix[v1][i]! =0&&mark[i].visit==-1) { //cout<<"此时next的i值是: "< returni; } returni; } //Setedge(v1,v2)towgt voidsetEdge(intv1,intv2,intwgt) { numEdge++;//ERROR matrix[v1][v2]=wgt; } voiddelEdge(intv1,intv2) {//Deleteedge(v1,v2) if(matrix[v1][v2]! =0) numEdge--; matrix[v1][v2]=0; } intweight(intv1,intv2) { returnmatrix[v1][v2]; } stringgetVal(intv) { returnmark[v].LessonName; } intgetMark(intv) { returnmark[v].visit; } voidsetVal(intv,stringval) { mark[v].LessonName=val; } voidsetMark(intv,intMark) { mark[v].visit=Mark; } voidsetfirst(intv) { mark[v].first++; } voidFind(stringsearch,int&v) { for(inti=0;i { if(mark[i].LessonName==search) { v=i; return; } } cout<<"路径错误"< return; } voidDFS(Graph*G,queue { for(intv=0;v if(mark[v].first==0) { Q->push(v); setMark(v,1); } while(Q->size()! =0) { inti=Q->front();//获取Q栈首元素 Q->pop();//弹出Q栈 L->push(i);//进L栈 for(intw=first(i);w { mark[w].first--; if(mark[w].first==0) { Q->push(w);setMark(w,1); } } } for(inti=0;i { if(getMark(i)==-1)//为0时表示还未被删除,图不为空 { cout<<"课程输入错误! 教学计划编制失败,请重新输入。 "< exit(0); } } } }; intmain() { intn; intv1; intv2; intjudge; stringCh; stringCh1; stringCh2; queue queue intD[100]; intcount=0; cout<<"请输入课程总数: "; cin>>n; if(n<=0) { cout<<"输入错误重新输入(大于零的整数)"< cout<<"请输入课程总数: "; cin>>n; } Grapha(n); for(inti=0;i { cout<<"请输入课程"< "; cin>>Ch; a.setVal(i,Ch); } for(inti=0;i { judge=0; cout< cin>>judge; if(judge) { a.setfirst(i); cout<<"请输入先修课程的名称: "; cin>>Ch1; a.Find(Ch1,v1); a.setEdge(v1,i,10); } } cout<<"课程表的排序为: "< a.DFS(&a,&Q,&L); for(inti=0;i { intj=L.front(); cout< L.pop(); } system("pause"); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 实验 教学计划 编制