湖大数据结构教学计划编制问题.docx
- 文档编号:9262784
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:21
- 大小:193.18KB
湖大数据结构教学计划编制问题.docx
《湖大数据结构教学计划编制问题.docx》由会员分享,可在线阅读,更多相关《湖大数据结构教学计划编制问题.docx(21页珍藏版)》请在冰豆网上搜索。
湖大数据结构教学计划编制问题
HUNANUNIVERSITY
课程实验报告
题目:
教学计划编制问题
学生姓名:
何进
学生学号:
201326010116
专业班级:
软件1301
指导老师:
李晓鸿老师
完成日期:
2014年12月16号
一.需求分析
输入形式
在该程序中,用户需要输入参数:
课程总数,每门课的课程号(固定占输入参数:
课程总数,每门课的课程号(固定占3位的字母数字串)和边的总数。
当用户输入有误时,提示用户输入有误并重新输入。
具体格式如下:
请输入课程总数:
请输入边的总数:
请输入第xx门课程的课程号(固定占3位的字母数字串):
请输入第xx条边:
输出形式
若根据输入条件问题无解,则报告适当的信息;否则将教学计划输出到DOS界面并存到用户指定的文件中。
具体格式如下:
此问题无解。
课程修读顺序为:
教学计划已存入文件中。
程序功能
本程序可以通过对图进行拓扑排序来解决教学计划的编制问题
测试数据
1.请输入课程总数:
2
请输入边的总数:
1
请输入第一门课程的课程号(占3位的字母数字串):
a01
请输入第二门课程的课程号(占3位的字母数字串):
a02
请输入第一条边:
a01a02
课程修读顺序为:
a01a02
2.请输入课程总数:
3
请输入边的总数:
3
请输入第一门课程的课程号(占3位的字母数字串):
a01
请输入第二门课程的课程号(占3位的字母数字串):
a02
请输入第三门课程的课程号(占3位的字母数字串):
a02
请输入第一条边:
a01a02
请输入第一条边:
a02a03
请输入第一条边:
a03a01
此问题无解
3.请输入课程总数:
3
请输入边的总数:
3
请输入第一门课程的课程号(占3位的字母数字串):
a01
请输入第二门课程的课程号(占3位的字母数字串):
a02
请输入第三门课程的课程号(占3位的字母数字串):
a02
请输入第一条边:
a01a03
请输入第一条边:
a02a03
请输入第一条边:
a03a01
此问题无解
4.请输入课程总数:
4
请输入边的总数:
4
请输入第一门课程的课程号(占3位的字母数字串):
a01
请输入第二门课程的课程号(占3位的字母数字串):
a02
请输入第三门课程的课程号(占3位的字母数字串):
a02
请输入第四门课程的课程号(占3位的字母数字串):
a02
请输入第一条边:
a04a02
请输入第二条边:
a02a03
请输入第三条边:
a03a01
请输入第四条边:
a04a01
课程修读顺序为:
a04a02a03a01
5.请输入课程总数:
-1
结束程序
二.概要设计
抽象数据类型
因为各个课程的修读之间的关系是非线性的,而且具有结构网状特性,并且课程修读关系是有向的,所以选择有向图来表示教学计划;
由于邻接表的时间复杂度为Θ(),比邻接矩阵的时间代价要小,所以我选用邻接表来存储该有向图;
有向图的ADT设计:
数据对象:
G=(V,E),其中V表示顶点集合,E表示边集合
数据关系:
VR={
基本操作:
intn();//图中顶点个数
inte();//图边数
intfirst(int);//该点的第一条临边
intnext(int,int);//该点的第二条临边
voidsetEdge(int,int,int);//为边设置权值
voidsetMark(int,int);//设置该顶点的标志值
intgetMark(int);//获得该顶点的标志值
图的顶点ADT设计:
数据对象:
课程的课程号(占3位的字母数字串)
数据关系:
{vi|i=1,2,3……n}
基本操作:
intposition();//获取顶点位置
算法基本思想
1.建表:
通过用户输入的课程个数初始化一个有向图的临接矩阵,根据用户输入的课程修读的先后关系构建完整的临接矩阵,并完成图的构建。
为了检验图中顶点是否经过拓扑排序,为每个顶点初始化一个标志值0,当一个顶点经过拓扑排序后更改该顶点标志值1。
2.排序:
从有向图中选取一个没有前驱的顶点,将该顶点的数据入队列。
然后从有向图中删去此顶点以及所有以它为尾的弧,并把该顶点标志值改为1。
重复上述步骤,直至所有点的标志值都为1(图空),或者图不空但找不到无前驱的顶点为止。
若无标志值为0的顶点,则输出顶点序列并将其存入文件中,若还有1个或1个以上的标志值为0的顶点,则输出此问题无解
程序基本流程
此程序主要包括4个流程:
1.输入流程:
由用户输入各项参数:
课程总数,每门课的课程号(固定占输入参数:
课程总数,每门课的课程号(固定占3位的字母数字串)和直接先修课的课程号。
当用户输入有误时,提示用户输入有误并重新输入;
2.构建流程:
根据用户构建相应的临接矩阵;
3.排序流程:
将该图的顶点依次进行拓扑排序,并将排序结果存入队列;
4.输出流程:
若最后所有顶点标志值都为1,则输出队列中的课程修读顺序,将其存入文件中。
若最后有1个或1个以上顶点标志值为0,则输出该问题无解
三.详细设计
物理数据类型
1.图和边的相邻矩阵实现:
边的实现:
classEdge
{
public:
intvertex,weight;
Edge(){vertex=-1;weight=-1;}
Edge(intv,intw){vertex=v;weight=w;}
};
图的相邻矩阵实现:
classGraphm
{
private:
intnumVertex,numEdge;
int**matrix;
int*mark;
public:
Graphm(intnumVert){
inti,j;
numVertex=numVert;//顶点数
numEdge=0;
mark=newint[numVert];
for(i=0;i mark[i]=0;//每一个顶点的标志值初始化为0 matrix=(int**)newint*[numVertex]; for(i=0;i matrix[i]=newint*[numVertex];for(i=0;i for(j=0;j } ~Graphm() { delete[]mark; for(inti=0;i delete[]matrix[i]; delete[]matrix;}//析构函数 intn(){returnnumVertex;}//顶点个数 intfirst(intv)//该顶点的第一条邻边 { inti; for(i=0;i if(matrix[v][i]! =0)returni; returni; } intnext(intv1,intv2)//获得v1的邻居v2 {inti; for(i=v2+1;i if(matrix[v1][i]! =0)returni; returni;} voidsetEdge(intv1,intv2)//设置有向图的边 { if(matrix[v1][v2]==0) numEdge++; matrix[v1][v2]=1; } intgetMark(intv)//获取顶点标记的值 {returnmark[v];} intsetMark(intv,intval)//设置访问的标记{mark[v]=val;} } 图顶点Node类设计: classNode { private: stringclassNum;//课程编号 intposition;//顶点位置 public: Node(stringc,intp){classNum=c;position=p;} intposition(); {returnposition;}//获取顶点位置 } 队列的实现 classQueue { private: intsize; Node*front; Node*rear; public: Queue(intsz){front=NULL;rear=NULL;size=0} ~queue(){delete[]front;delete[]rear;}; voidclear() {while(front! =NULL) {rear=front; front=front->next; deleterear; } rear=NULL;size=0; }//队列的清空 boolenqueue(constNode&it) { if(rear=NULL) front=rear=newLink else { rear->next=newLink rear=rear->next; } size++; returntrue; }//入队 booldequeue(Node&it) { if(size==0)returnfalse; it=front->element; Node*ltemp=front; front=front->next deleteltemp; if(front==NULL)rear=NULL; siz--; returntrue; }//出队 intlength()const{returnsize;}//队列的长度 } TopologicalSort的实现 voidtopsort(Graph*G,Queue intCount[G->n()]; intv,w; for(v=0;v for(v=0;v for(w=G->first(v);w w=G->next(v,w)) Count[w]++;//Addtov2'scount for(v=0;v if(Count[v]==0)//Noprereqs Q->enqueue(v); while(Q->length()! =0){ Q->dequeue(v); printout(v);//PreVisitforV for(w=G->first(v);w w=G->next(v,w)){ Count[w]--;//Onelessprereq if(Count[w]==0)//Nowfree Q->enqueue(w); } } } 算法具体步骤 1.输入: 由用户输入各项参数: 课程总数,每门课的课程号(固定占输入参数: 课程总数,每门课的课程号(固定占3位的字母数字串)和直接先修课的课程号。 当用户输入有误时,提示用户输入有误并重新输入; 2.构建图: 根据用户构建相应的临接表; 3.拓扑排序: 将该图的顶点依次进行拓扑排序,并将排序结果存入队列; 4.输出: 若最后所有顶点标志值都为1,则输出队列中的课程修读顺序,将其存入文件中。 若最后有1个或1个以上顶点标志值为0,则输出该问题无解 input(classNu);//课程总数 GraphmG;QueueQ; for(inti=0;i { input(className[i]);//课程编号 input(rearClass);//该课程的先修课程 if(rearClass! =’N’) {G.setEdge(rearClass,i); G.setMark(i,1);} } for(intj=0;j { if(G.getMark(i)==0) output: ”此问题无解。 ”; exit; }//判断是否有解 topsort(G,Q);//排序及输出 函数关系调用 输入 构建临接矩阵: G.setEdge(classNum1,classNum2,1) 标记函数: G.Mark(I,1) 拓扑排序: topsort(G,Q) 判断是否有解: 存在G.getMark(i)==0? 输出: output 算法时空分析 构建一个临接矩阵的时间代价是Ɵ(|V|2),拓扑排序的时间代价是Ɵ(|V|),所以该算法总的时间代价是Ɵ(|V|2) 输入输出格式 输入: input(classNu);//课程总数 for(inti=0;i { input(className[i]);//课程编号 input(rearClass);//该课程的先修课程 } 请输入课程总数: 请输入第xx门课程的课程号(固定占3位的字母数字串): 该课程的先修课是(若没有则输入N,有则输入课程号): 输出: for(intj=0;j { if(G.getMark(i)==0) output: ”此问题无解。 ”; }//判断是否有解 topsort(G,Q);//topsort函数中的输出功能 此问题无解。 课程修读顺序为: 四.调试分析 程序需要用到较多指针,因而首次调试时出现了溢出的情况,后来通过设置断点的方法解决了这个问题 五.测试结果 六.用户使用说明 1.本程序可以通过构建一个有向图来实现教学计划的编排; 2.用户需输入每门课的课程号(固定占输入参数: 课程总数,每门课的课程号(固定占3位的字母数字串)和边的总数以及各条边。 当用户输入有误时,提示用户输入有误并重新输入。 3.在边的输入中,请勿输入之前未经输入的课程名字,否则程序会出错! 七.实验心得 通过该实验,我掌握了通过构建邻接表来存储图的方法以及拓扑排序的使用方法。 #include #include usingnamespacestd; intjudge() { //对输入的合法性进行判断并返回有效的输入 inttemp; cin.sync();//清空输入流缓冲区 cin>>temp; while (1) { if(cin.fail()||cin.bad()||cin.get()! ='\n')//验证输入是否合法,其中cin.fail()和cin.bad()解决输入字符串和溢出的问题 cout<<"输入有误,请重新输入: "< elsebreak;//输入合法则跳出循环 cin.clear();//清空输入流缓冲区标志位,以免影响下次输入 cin.sync(); cin>>temp; } returntemp; }; classNode {//结点类 public: stringclassName; intposition;//位置 Node*next; boolvisit;//是否被访问 Node(){visit=false;next=NULL;position=0;className='';} }; classList {//线性表类 public: intnum; Node*head; Node*rear; Node*fence; List(){num=0;head=fence=rear=newNode();} ~List(){delete[]head;delete[]rear;delete[]fence;} voidinsert(intv,stringch) {//插入元素 Node*current=newNode(); current->className=ch; current->position=v; fence->next=current; fence=current; num++; } }; classGraph {//图类 private: intnumVertex; intnumEdge; List*list; public: Graph(intv,inte){numVertex=v;numEdge=e;list=newList[v];} ~Graph(){delete[]list;} voidpushVertex() {//读入点 stringch; for(inti=0;i { cout<<"请输入课程"< "; cin>>ch; list[i].head->className=ch; list[i].head->position=i; } } voidpushEdge() {//读入边 stringch1,ch2; intpos1,pos2; for(inti=0;i { cout<<"请输入第"< "; cin>>ch1>>ch2; for(intj=0;j { if(list[j].head->className==ch1) pos1=j;//找到该字母对应的位置 if(list[j].head->className==ch2) { pos2=list[j].head->position; break; } } list[pos1].insert(pos2,ch2); } } voidtopsort() {//拓扑排序 inti; int*count=newint[numVertex]; for(i=0;i count[i]=0;//数组初始化 for(i=0;i { Node*p=list[i].head; while(p->next! =NULL) { count[p->next->position]++;//计算每个点的入度 p=p->next; } } inttop=-1,m=0,j,k; for(i=0;i if(count[i]==0) { count[i]=top;//找到第一个入度为0的点 top=i; } while(top! =-1) { j=top; top=count[top]; cout< m++; Node*p=list[j].head; while(p->next! =NULL){ k=p->next->position; count[k]--;//当起点被删除,时后面的点的入度-1 if(count[k]==0) { count[k]=top; top=k; } p=p->next; } } } if(m cout<<"此问题无解"< delete[]count; } }; intmain() { intclassAmo,sideAmo; cout<<"请输入课程总数: \n"; cin>>classAmo; if(classAmo==-1)return0; cout<<"请输入边的总数: "< sideAmo=judge(); GraphG(classAmo,sideAmo); G.pushVertex(); G.pushEdge(); cout<<"课程修读顺序为: \n"; G.topsort(); cout< system("pause>>NUL"); return0; } className<<"";
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 教学计划 编制 问题
![提示](https://static.bdocx.com/images/bang_tan.gif)