数据结构实验五教学计划编制课案Word下载.docx
《数据结构实验五教学计划编制课案Word下载.docx》由会员分享,可在线阅读,更多相关《数据结构实验五教学计划编制课案Word下载.docx(20页珍藏版)》请在冰豆网上搜索。
![数据结构实验五教学计划编制课案Word下载.docx](https://file1.bdocx.com/fileroot1/2022-12/30/668ccf79-b1fd-4387-9dc0-b3a27e046844/668ccf79-b1fd-4387-9dc0-b3a27e0468441.gif)
①.正常的输入
输入:
输入课程总数:
3
请输入课程1的名称:
小学数学
请输入课程2的名称:
初中数学
请输入课程3的名称:
大学数学
小学数学是否有先修(1/0):
初中数学是否有先修(1/0):
1
请输入先修课程的名称:
高中数学是否有先修(1/0):
输出:
小学数学初中数学高中数学
②.正常的输入
4
2
请输入课程4的名称:
1是否有先修(1/0):
2是否有先修(1/0):
3是否有先修(1/0):
4是否有先修(1/0):
4132
③.有两个先修课程的情况
A
B
C
D
A是否有先修(1/0):
B是否有先修(1/0):
C是否有先修(1/0):
D是否有先修(1/0):
ABCD
④.有三个先修课程的情况
DABC
⑤.所有课程无先修
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={<
v,w>
|v,w∈V且P(v,w)}
<
表示从v到w的一条弧,并称v为弧头,w为弧尾。
intn();
//返回图中的顶点数
intfirst(int);
//返回该点的第一条邻边
intnext(int);
//返回该店的下一条邻边
voidsetEdge(int,int,int);
//为有向边设置权值
voidFind(stringsearch,int&
v)
intn()
ADTqueue{
前指针front,后指针rear
R={<
ai-1,ai>
|ai-1,ai∈car,i=1,2,3….n}
约定a1为队列头,an为队列尾。
queue();
//队列结构初始化
~queue();
//结构销毁操作
boolpush(constint&
it);
//数据入列
boolpop(int&
//数据出列
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<
numVertex;
i++)
{
mark[i].visit=-1;
//包括初始化被访问标记和先修标记
mark[i].first=0;
}
matrix=(int**)newint*[numVertex];
//Makematrix
matrix[i]=newint[numVertex];
i++)//Edgesstartw/0weight
for(intj=0;
j<
j++)matrix[i][j]=0;
}
②.先修信息的存储:
由用户输入是否有先修课程后,用户每输入一个先修课程,就将这个课程对应的先修标记加1.
cout<
a.getVal(i)<
"
是否有先修(1/0)"
;
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队列,再把该顶点打印出来,同时将其所有相邻顶点的先修关系计数器减一。
重复将队列B中首元素输出并删除,直到队列为空,就是课程表的排序。
voidDFS(Graph*G,queue<
int>
*Q,queue<
*L)
for(intv=0;
v<
n();
v++)
if(mark[v].first==0)
Q->
push(v);
setMark(v,1);
while(Q->
size()!
=0)
inti=Q->
front();
//获取Q栈首元素
pop();
//弹出Q栈
L->
push(i);
//进L栈
for(intw=first(i);
w<
w=next(i,w))
mark[w].first--;
if(mark[w].first==0)
{
Q->
push(w);
setMark(w,1);
}
for(inti=0;
if(getMark(i)==-1)//为0时表示还未被删除,图不为空
课程输入错误!
<
endl;
exit(0);
3.算法的时空分析及改进设想
因为图的邻接矩阵是一个|V|×
|V|矩阵,所以邻接矩阵的空间代价为Θ(|V|^2),对于有n个顶点的和E条弧的有向图而言,对此图的拓扑排序算法时间复杂度为Θ(V+E)
4.输入和输出的格式
1.输入课程数n
cout<
请输入课程总数:
cin>
n;
if(n<
cout<
输入错误重新输入(大于零的整数)"
2.输入每门课的课程编号
for(inti=0;
请输入课程"
i+1<
名称:
Ch;
a.setVal(i,Ch);
3.获得先修的课程编号
judge=0;
1.编制成功,把队列S中的顶点序列输出。
cout<
课程表的排序为:
a.DFS(&
a,&
Q,&
L);
intj=L.front();
a.getVal(j)<
L.pop();
2.编制失败,图中有回路,输出错误信息,结束程序。
if(G.getMark(i)==0)//为0时表示该顶点未经过拓扑排序
{
cout<
endl;
exit(0);
四.调试分析
DFS问题,书上思路很明确并且有很多源码,没有大的问题。
五.测试结果
1.正常的输入输出
3.有两个先修课程的情况
附录
#include<
iostream>
queue>
fstream>
string>
iomanip>
usingnamespacestd;
classPoint
public:
stringLessonName;
intvisit;
intfirst;
//1有先修,0无
};
classGraph
{//Implementadjacencymatrix
private:
intnumVertex,numEdge;
//Storenumberofverticesedges
int**matrix;
//Pointertoadjacencymatrix
Point*mark;
//Pointertomarkarray
Graph(intnumVert)
{//Makegraphw/numVertvertices
~Graph()
delete[]mark;
delete[]matrix[i];
delete[]matrix;
returnnumVertex;
inte()
returnnumEdge;
intfirst(intv)
{//Returnv'
sfirstneighbor
inti;
if(matrix[v][i]!
=0&
mark[i].visit==-1)returni;
returni;
//Returnnifnone
intnext(intv1,intv2)
//Getv1'
sneighborafterv2
for(i=v2+1;
if(matrix[v1][i]!
mark[i].visit==-1)
//cout<
此时next的i值是:
v1+1<
i+1<
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]!
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;
if(mark[i].LessonName==search)
v=i;
return;
路径错误"
return;
voidDFS(Graph*G,queue<
intmain()
intn;
intv1;
intv2;
intjudge;
stringCh;
stringCh1;
stringCh2;
queue<
Q;
L;
intD[100];
intcount=0;
if(n<
Grapha(n);
system("
pause"
);
return0;