教学计划编制问题 实验5.docx

上传人:b****6 文档编号:3458948 上传时间:2022-11-23 格式:DOCX 页数:17 大小:208.52KB
下载 相关 举报
教学计划编制问题 实验5.docx_第1页
第1页 / 共17页
教学计划编制问题 实验5.docx_第2页
第2页 / 共17页
教学计划编制问题 实验5.docx_第3页
第3页 / 共17页
教学计划编制问题 实验5.docx_第4页
第4页 / 共17页
教学计划编制问题 实验5.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

教学计划编制问题 实验5.docx

《教学计划编制问题 实验5.docx》由会员分享,可在线阅读,更多相关《教学计划编制问题 实验5.docx(17页珍藏版)》请在冰豆网上搜索。

教学计划编制问题 实验5.docx

教学计划编制问题实验5

HUNANUNIVERSITY

实验五最终报告

 

题目:

教学计划编制问题

学生姓名

学生学号

专业班级

指导老师

完成日期2014年5月15日

一、需求分析

1.输入形式:

用户通过键盘输入课程总数、每门课的课程编号(固定占3位的字母数字串)和直接先修的课程号等的参数。

不对非法输入做处理,假定输入的数据都合法。

2.输出形式:

如果拓扑排序成功,输出拓扑排序后的教学计划编制的顺序;

如果拓扑排序不成功,输出排序错误信息,结束程序。

3.程序功能:

对于用户输入的一组课程编号,根据输入的先修顺序创建邻接矩阵进行存储,并输出拓扑排序后的课程编号的顺序。

4.测试数据

输入:

输入课程总数:

3

输入每门课的课程编号:

A01

是否有直接先修的课程(T/F):

F

输入每门课的课程编号:

A02

是否有直接先修的课程(T/F):

T

先修课程编号:

A01

是否有直接先修的课程(T/F):

F

输入每门课的课程编号:

A03

是否有直接先修的课程(T/F):

T

先修课程编号:

A02

是否有直接先修的课程(T/F):

F

输出:

教学计划编制完成,课程修读顺序为:

A01,A02,A03

(输入有误)课程输入错误!

教学计划编制失败,请重新输入。

二、概要设计

抽象数据类型

题设要求使用一个有向图表示教学计划,顶点表示某门课程,有向边表示课程之间的先修关系,数据的对象是图中的每一个顶点和有向边。

由此为本问题确定一个图的数据关系。

拓扑排序可以用顶点入度为0的方法实现,所以为实现拓扑排序的顶点顺序的存放,创建一个队列来存放。

图的ADT

数据对象:

V,R(分别代表某门课程的顶点组成的一个顶点集 V 和代表课程先修关系的有向弧边组成的一个弧集 R。

数据关系:

VR={|v,w∈V且P(v,w)}

表示从v到w的一条弧,并称v为弧头,w为弧尾。

基本操作:

intn();//返回图中的顶点数

intfirst(int);//返回该点的第一条邻边

intnext(int);//返回该店的下一条邻边

voidsetEdge(int,int,int);//为有向边设置权值

intgetMark(int);//获得顶点的标志值

voidsetMark(int);//为顶点设置标志值

队列ADT

数据对象:

int

数据关系:

R={|ai-1,ai∈car,i=1,2,3….n}

约定a1为队列头,an为队列尾。

基本操作:

queue();//队列结构初始化

~queue();//结构销毁操作

boolpush(constint&it);//数据入列

boolpop(int&it);//数据出列

intsize();//获取队列长度

算法的基本思想

通过用户输入的顶点的个数(课程数)初始化一个表示有向图的相邻矩阵,课程编号作为相邻矩阵的行列值以及有向边的关系(课程先修关系)完成一个有向图的构建。

为了检验图中顶点是否都经过拓扑排序,为每个顶点初始化一个标志值0,当一个顶点经过拓扑排序后更改该顶点标志值0。

对相邻矩阵棕的顶点进行入度为0的方法进行拓扑排序。

排序结束后,遍历一次图中所有顶点的标志值,当有一个标志值为0时,输出错误信息,结束程序。

否则,排序成功,输出排序后的顶点序列。

程序的流程

(1)初始化模块:

输入课程总数,再输入相应数量的课程编号及每个课程的先修课程,用这些信息初始化一个有向图。

(2)拓扑排序模块:

对有向图进行拓扑排序。

(3)输出模块:

根据有向图是否为空输出。

为空时,输出拓扑排序结果;不为空时输出输入错误提示。

各层次模块之间的调用关系

三、详细设计

物理数据类型

由于用户输入的课程个数不定,所以存储拓扑排序后的顶点的个数不定,由此用链式队列来存储排序后的顶点。

为了检查图中是否有回路,把每一个顶点的标志值初始化为0。

(一)有向图的基本操作

1.初始化一个有向图

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

matrix[i][j]=0;

}

2.有向图的销毁

~Graphm()

{

delete[]mark;

for(inti=0;i

delete[]matrix[i];

delete[]matrix;//销毁相邻矩阵

}

3.获取第一个邻居

intfirst(intv)//返回该点的第一条邻边

{

inti;

for(i=0;i

if(matrix[v][i]!

=0)returni;//当顶点和顶点i有边时,返回顶点i的值

returni;

}

intnext(intv1,intv2)//获得v1的邻居v2

{

inti;

for(i=v2+1;i

if(matrix[v1][i]!

=0)returni;

returni;

}

4.其他基本操作

voidsetEdge(intv1,intv2)//设置有向图的边

{

if(matrix[v1][v2]==0)

numEdge++;

matrix[v1][v2]=1;

}

intgetMark(intv)//获取顶点标记的值

{returnmark[v];}

intsetMark(intv,intval)//设置访问的标记

{mark[v]=val;}

(二)拓扑排序

找到第一个入度为0 的点存入队列中,从有向图中删去此顶点以及所有以它为尾的弧,再在这些点中找入度为0 的点。

重复上述操作,直至图空,或者图不空但找不到无前驱的顶点为止,此时返回该队列。

queuetopsort(GraphmG,queueQ,queueL,intn)

{

intcount[100];

intv,w,i;

for(v=0;v

{count[v]=0;}

for(v=0;v

for(w=G.first(v);w

count[w]++;

for(v=0;v

if(count[v]==0)//找到度为0的点

{Q.push(v);G.setMark(v,1);}//顶点进队列,并更改顶点标志值为1

while(Q.size()!

=0)

{

i=Q.front();

Q.pop();

L.push(i);

for(w=G.first(i);w

{

count[w]--;//顶点度减一

if(count[w]==0)//找到度为0的点

{Q.push(w);G.setMark(w,1);}//顶点进队列,并更改顶点标志值为1

}

}

returnL;//返回存放排序后顶点的队列

}

(三)队列基本操作

//压入队列

boolpop(char*&it)

{

if(length()==0)returnfalse;

it=front->elem;

qnode*ltemp=front;

front=front->next;

deleteltemp;

if(front==NULL)rear=NULL;

size--;

returntrue;

}

//出队列

boolpush(constchar*&it){

if(rear==NULL)

front=rear=newqnode(it,NULL);

else//append

{

rear->next=newqnode(it,NULL);

rear=rear->next;

}

size++;

returntrue;

}

//获取队列长度

intsize()const

{returnsize;}

最后,判断图中是否有回路。

可以通过遍历图中的每一个顶点的标记值,如果有一个为0,那么说明图中存在回路。

for(i=0;i

{if(G.getMark(i)==0)//为0时表示该顶点未经过拓扑排序

{cout<<"课程输入错误!

教学计划编制失败,请重新输入。

"<

exit(0);}}

算法的具体步骤

创建一个数组存储顶点信息,再构建一个邻接矩阵存储输入的课程编号(顶点),和课程先修关系(有向边)构成的有向图的信息,然后对邻接矩阵中的图的信息进行拓扑排序,把排序结果存放在一个队列中。

如果一次排序结束后,遍历顶点标志值有为0,输出输入错误提示,结束程序;否则,输出队列中存储的课程编号序列。

流程图如下:

伪代码如下,

charv[100][5];

charv1[4],v2[4];

GraphmT;

queueS;

cin.get(n);//输入课程总数n

T.CreatGraphm(n);

cin.get(v);//输入每门课的编号,保存在*v[4]数组中

for(i=0;i

{

cout<

";

cin>>ch;

while(ch=='T')

{

GetNum(n2);//输入先修课程编号

T.setEdge(n2,i);//n2在前表示先修的顺序

cout<<"是否有直接先修的课程(T/F):

";

cin>>ch;

}

}

S=topsort(T,Q,L,n);//对图T进行拓扑排序,排序序列存储在队列中返回到S

cout<<"教学计划编制完成,课程修读顺序为:

"<

printout(S);//输出排序后的顶点序列

}

算法的时空分析及改进设想

因为图的邻接矩阵是一个|V|×|V|矩阵,所以邻接矩阵的空间代价为Θ(|V|^2),对于有n个顶点的和E条弧的有向图而言,对此图的拓扑排序算法时间复杂度为Θ(V+E)

输入和输出的格式

输入:

1.输入课程数n----cin.get(n);

cout<<"输入课程总数:

";

cin<

2.输入每门课的课程编号----cin.get(v);

for(i=0;i

{

cout<<"输入每门课的课程编号:

"<

cin.get();

cin.getline(v1,4);

strcpy(v[i],v1);//要用字符串拷贝函数,用等号不能正确的赋值!

}

3.获得先修的课程编号----GetNum(n2);

cout<<"先修课程编号:

";

cin.get();

in.getline(v2,4);

n2=getNum(v,n,v2);

输出:

1.编制成功,把队列S中的顶点序列输出。

----printout(S);

for(i=0;i

{

j=S.front();

cout<

S.pop();

}

2.编制失败,图中有回路,输出错误信息,结束程序。

if(G.getMark(i)==0)//为0时表示该顶点未经过拓扑排序

{

cout<<"课程输入错误!

教学计划编制失败,请重新输入。

"<

exit(0);

}

四、测试数据

编制成功,003->001->002

编制失败,001->002,002->001

附上完整代码

#include

#include

#include

usingnamespacestd;

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(){}

voidCreatGraphm(intnumVert)

{

inti,j;

numVertex=numVert;//vertex顶点数

numEdge=0;

mark=newint[numVert];

for(i=0;i

mark[i]=0;

matrix=(int**)newint*[numVertex];

for(i=0;i

matrix[i]=newint[numVertex];

for(i=0;i

for(j=0;j

matrix[i][j]=0;

}

~Graphm()

{

delete[]mark;

for(inti=0;i

delete[]matrix[i];

delete[]matrix;

}

intn(){returnnumVertex;}

inte(){returnnumEdge;}

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];}

voidsetMark(intv,intval)

{mark[v]=val;}

};

queuetopsort(GraphmG,queueQ,queueL,intn)

{

intcount[100];

intv,w,i;

for(v=0;v

{

count[v]=0;

}

for(v=0;v

for(w=G.first(v);w

count[w]++;

for(v=0;v

if(count[v]==0)

{Q.push(v);G.setMark(v,1);}

while(Q.size()!

=0)

{

i=Q.front();

Q.pop();

L.push(i);

for(w=G.first(i);w

{

count[w]--;

if(count[w]==0)

{Q.push(w);G.setMark(w,1);}

}

}

for(i=0;i

{

if(G.getMark(i)==0)//为0时表示还未被删除,图不为空

{

cout<<"课程输入错误!

教学计划编制失败,请重新输入。

"<

exit(0);

}

}

returnL;

}

intgetNum(char(*vert)[5],intn,char*s)

{

for(inti=0;i

if(strcmp(vert[i],s)==0)

returni;}

}

voidmain()

{

intn;

charv[100][5];

charv1[4],v2[4];

charch;

inti,n2,j;

GraphmT;

queueQ;

queueL;

queueS;

cout<<"输入课程总数:

";

cin>>n;

T.CreatGraphm(n);

for(i=0;i

{

cout<<"输入每门课的课程编号:

"<

cin.get();

cin.getline(v1,4);

strcpy(v[i],v1);//要用字符串拷贝函数,用等号不能正确的赋值!

}

for(i=0;i

{

cout<

";

cin>>ch;

while(ch=='T')

{

cout<<"先修课程编号:

";

cin.get();

cin.getline(v2,4);

n2=getNum(v,n,v2);

T.setEdge(n2,i);//n2在前表示先修的顺序

cout<<"是否有直接先修的课程(T/F):

";

cin>>ch;

}

//cout<

}

cout<

S=topsort(T,Q,L,n);

//////////////

cout<

cout<<"教学计划编制完成,课程修读顺序为:

"<

for(i=0;i

{

j=S.front();

cout<

S.pop();

}

cout<

}

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

当前位置:首页 > 小学教育 > 语文

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

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