《教学计划编制问题》数据结构课程设计说明书Word文档格式.docx
《《教学计划编制问题》数据结构课程设计说明书Word文档格式.docx》由会员分享,可在线阅读,更多相关《《教学计划编制问题》数据结构课程设计说明书Word文档格式.docx(36页珍藏版)》请在冰点文库上搜索。
输出教学计划到用户指定的文件中,计划表格格式自行设计,若无结果可报告适当的信息。
2.2功能需求分析
本系统主要实现对大学中每个专业的教学计划进行设计,需要实现以下几个方面的功能:
(1)创建存储结构:
创建邻接表。
(2)数据的输入:
学期总数,课程数,一学期的学分上限,每门课的课程号(固定占2位的数字串)、学分和直接先修课的课程号。
(3)数据的处理:
对输入的数据进行计算。
(4)结果的输出:
输出各门课程所对应的学分,以及每学期各门课程的安排。
第3章系统设计
3.1总体设计
允许用户指定下列两种编排策略之一:
采用第二种策略,使课程尽可能地集中在前几个学期中,根据教学计划中的课程及其关系和学分定义图的顶点和边的结构体,创建图,结合先修关系的AOV网,采用邻接链表存储和使用前插法,通过菜单显示代号所对应课程及课程的先修课程,运用拓扑排序将课程排序后并决定出每学期所学课程,最后输出图G的信息,将图的顶点和弧边输出。
具体流程图如图3.1所示。
图3.1系统功能结构图
首先,初始化栈,构造一个空栈S,判定这个栈是否为空栈,如果是,则进行下一步操作,否则,返回错误;
接下来对各个顶点求入度,将入度为零的顶点存入数组,当所有入度为零的顶点都存入数组后,执行完毕。
具体流程图如图3.2所示。
初始化栈InitStack(S)
对各顶点求入度,并存入数组InDegree[i]中(i=0…n)
依次将入度为0的顶点存入栈中
推出栈顶的一个元素(入度为零的顶点号)至i,输出i,计数器加1(Count++)
对以i号顶点为尾弧的每个邻接点的入度减1,并将入度减1后为零的顶点号压入栈中,输出i,计数器加1(Count++)
n个顶点全输出
Return
ERROR
OK
栈是否为空?
Y
N
图3.2拓扑排序流程图
3.2主要模块简介
1、管理员
要进入管理员界面,首先需要输入用户名和密码。
输入正确的用户名和密码后,即可进入管理员界面;
若输入错误,则提示输入正确的用户名或密码。
2、主函数
本程序主要调用两个模块:
主程序模块---->
拓扑排序模块,调用关系简单,通过主函数主要调用TopoSort()输出G顶点的拓扑排序,
Display()输出图的邻接矩阵,
CreateGraph()
生成图,用来实现对教学计划的编制。
3、拓扑排序
利用课程之间的先修关系,运用拓扑排序进行学期课程安排(4个学期),每学期都有学分上限,而每学期应学课程的学分应在学分上限内,超过学分上限后,将移到下一学期课程安排中。
在满足课程先修关系和各学期课程安排的情况下,如果某门课程的学分超过该学期的学分上限,则系统返回值为Error,提示错误,需要进行修改,必须保证该学期的各课程学分不会超过学分上限,这时系统返回值为OK。
第4章详细设计
4.1数据结构
1、图的数据结构
typedefstructArcNode//表结点
{
intadjvex;
//该弧所指向的顶点的位置,弧的节点结构
structArcNode*nextarc;
//指向下一条弧的指针
}ArcNode;
//链表结点
typedefstructVNode//头结点
VertexTypedata;
//顶点信息
intgrades;
//存储学分信息
ArcNode*firstarc;
//指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM];
typedefstruct//图的数据结构
AdjListvertices;
//vertices存储课程名
intvexnum,arcnum;
//图的当前顶点数和弧数
}ALGraph;
2、栈的数据结构
typedefstructSqStack
SElemType*base;
SElemType*top;
intstacksize;
//分配的存储空间
}SqStack;
4.2抽象数据类型的定义
1、图的抽象数据类型定义
ADTGraph{
数据对象V:
V是具有相同特性的数据元素的集合,称为顶点集。
数据关系R:
R={VR}
VR={<
v,w>
|v,w
V且P(v,w),<
表示从v到w的弧,
谓词P(v,w)定义了弧<
的意义或信息}
基本操作P:
CreateGraph(&
G,V,VR);
初始条件:
V是图的顶点集,VR是图中弧的集合。
操作结果:
按V和VR的定义构造图G。
LocateVex(G,u)
图G存在,u和G中顶点有相同特征。
若G中存在顶点u,则返回该顶点在图中位置;
否则返回其他信息。
}ADTGraph
2、栈的抽象数据类型定义
ADTStack{
数据对象:
D={
|
ElemSet,i=1,2,...,n,n
}
数据关系:
R1={<
>
D,i=2,...,n}
约定
端为栈顶,
端为栈底。
基本操作:
InitStack(&
S)
构造一个空栈S。
StackEmpty(S)
栈S已存在。
若栈S为空栈,则返回TRUE,否则FALSE。
Pop(&
S,&
e)
栈S已存在且非空。
删除S的栈顶元素,并用e返回其值。
Push(&
S,e)
插入元素e为新的栈顶元素。
}ADTStack
intLocateVex(ALGraphG,VertexTypeu)/*查找图中某个顶点位置*/
intCreateGraph(ALGraph&
G)/*采用邻接表存储结构*/
voidDisplay(ALGraphG)/*输出图G的信息*/
voidFindInDegree(ALGraphG,intindegree[])/*求顶点的入度*/
intInitStack(SqStack&
S)/*栈的初始化*/
intStackEmpty(SqStackS)/*判空*/
intPop(SqStack&
S,SElemType&
e)/*出栈*/
intPush(SqStack&
S,SElemTypee)/*入栈*/
4.3设计说明
教学计划编制问题主要用的是算法是拓扑排序。
偏序指集合中仅有部分成员之间可比较,而全序指集合中全体成员之间可比较。
一个表示偏序的有向图可用来表示一个流程图。
它或者是一个施工流程图,或者是一个产品生产的流程图,再或者是一个数据流图(每个顶点表示一个过程)。
图中每一条边表示两个子工程之间的次序关系(领先关系)。
拓扑排序的主要步骤:
(1)在有向图中选一个没有前驱的顶点且输出之。
(2)从图中删除该顶点和所有以它为尾的弧。
(3)重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。
针对上述三步操作,我们可以用邻接表作为有向图的存储结构,且在头结点中增加一个存放顶点入度的数组(indegree)。
入度为零的顶点即为没有前驱的顶点,删除顶点及以它为尾的弧的操作,则可换以弧头顶点的入度减1来实现。
为了避免重复检测入度为零的顶点,可另设一栈暂存所有入度为零的顶点。
4.4算法说明
1、主函数的算法设计:
显示子菜单,调用各个子函数,最后退出程序,主要代码:
voidmain()
ALGraphG;
AdjListTemp;
printf0();
structName
name[N]={{"
1"
},{"
2"
3"
4"
5"
6"
7"
8"
9"
10"
11"
12"
}};
OUTPUT();
printf("
★****★****★教学计划编制系统★****★****★\n\n"
);
请输入学期的总数:
"
scanf("
%d"
&
TotalTerms);
请输入学期的学分上限:
MaxScores);
CreateGraph(G);
Display(G);
TopoSort(G,Temp,name);
2、各主要子函数的算法设计
(1)邻接表存储结构
代码:
intCreateGraph(ALGraph&
G)
inti,j,k;
VertexTypeva;
ArcNode*p;
请输入教学计划的课程数:
G.vexnum);
请输入各门课程的先修课程的总和(弧总数):
G.arcnum);
请输入%d门课程的课程代码(最多%d个字符,数字):
G.vexnum,MAX_NAME);
for(i=0;
i<
G.vexnum;
++i)//构造头结点
{
scanf("
%s"
G.vertices[i].data);
G.vertices[i].firstarc=NULL;
}
i++)
printf("
请输入第%d门课程的学分值:
i+1);
G.vertices[i].grades);
while(G.vertices[i].grades>
MaxScores||G.vertices[i].grades<
=0)
{
printf("
警告!
学分必须是在0到最大限制%d之间,请检查后再输入!
\n"
MaxScores);
//如果输入的学分大于上限或等于0,会出现警告
scanf("
}
请输入下列课程的先修课程(无先修课程输入0,结束也输入0)\n"
for(k=0;
k<
++k)//构造表结点链表,利用前插法
%s的先修课程:
G.vertices[k].data);
///
va);
//
while(va[0]!
='
0'
)//ikva
i=LocateVex(G,va);
//弧尾
j=k;
//弧头
p=(ArcNode*)malloc(sizeof(ArcNode));
p->
adjvex=j;
nextarc=G.vertices[i].firstarc;
//插在表头
G.vertices[i].firstarc=p;
}
system("
cls"
returnOK;
(2)拓扑排序
intTopoSort(ALGraphG,AdjListTemp,structNamename[])
inti,k,j=0,count,indegree[MAX_VERTEX_NUM];
SqStackS;
ArcNode*p;
FindInDegree(G,indegree);
//对各顶点求入度
InitStack(S);
//初始化栈
++i)//建零入度顶点栈S
if(!
indegree[i])Push(S,i);
//入度为0者进栈
count=0;
//对输出顶点计数
while(!
StackEmpty(S))
Pop(S,i);
%s(%d分),"
G.vertices[i].data,G.vertices[i].grades);
Temp[j++]=G.vertices[i];
//将当前的拓扑序列保存起来
++count;
//输出i号顶点并计数
for(p=G.vertices[i].firstarc;
p;
p=p->
nextarc)//对i号顶点的每个邻接点的入度减1
{
k=p->
adjvex;
if(!
(--indegree[k]))//若入度减为0,则入栈
Push(S,k);
}
if(count<
G.vexnum)
此有向图有回路,无法完成拓扑排序!
returnERROR;
else
为一个拓扑序列"
第5章编码与调试
5.1教学计划编制问题实例
针对大学各专业本科课程,根据课程之间的依赖关系制定课程安排计划,并满足各学期课程数尽量排在前几个学期。
例如:
一个信息与计算科学专业的学生必须学习的一系列基本课程(如表5.1所示),其中有些课是基础课,它独立于其他课程,如《程序设计基础》;
而另一些课程必须在学完作为它的基础的先修课程才能开始,如在学习《离散数学》之前要先学完它的先修课程《程序设计基础》。
这些先修课程定义了课程之间的先修关系。
课程编号
课程名称
先修课程
1
程序设计基础
无
2
离散数学
3
数据结构
1、2
4
汇编语言
5
语言的设计和分析
3、4
6
计算机原理
11
7
编译原理
5、3
8
操作系统
3、6
9
高等数学
10
线性代数
大学物理
12
数值分析
9、10、1
表5.1信息与计算科学专业的学生必须学习的课程
解答:
某个学生学习了4个学期,每个学期的学分上限为15,教学计划的课程数为12,12门课程对应的学分为3、4、4、3、2、3、3、2、3、2、4、3,根据上表的先修课程可得:
第一学期应学课程为:
高等数学、线性代数、大学物理、计算机原理、程序设计基础;
第二学期应学课程为:
离散数学、数据结构、操作系统、汇编语言、语言的设计和分析;
第三学期应学课程为:
编译原理、数值分析;
第四学期应学课程为:
课程优先关系有向图(如图5.1所示):
图5.1课程优先关系有向图
得到一个拓扑有序序列为
(9,10,11,6,1,2,3,8,4,5,7,12)
5.2程序运行结果
1、打开VC++6.0,输入教学计划编制问题程序,点击运行,首先进入系统主界面,输入用户名和密码(本系统用户名和密码均为123)进入管理员界面,如图5.2所示。
图5.2系统主界面
2、在管理员界面,我们可以看到教学计划编制菜单,按Enter进行下一步操作,如图5.3所示。
图5.3管理员界面
3、在操作界面里,我们按照系统提示输入某学生的学期课程编制的各类数据,如图5.4所示。
图5.4学期课程编制数据
4、根据该学生的课程编制数据,输出运行结果,如图5.5所示。
图5.5运行结果
第6章总结
通过这次课程设计我们学到了很多东西,如程序的模块化设计思想,同时也加深了对数据结构这门课程的理解和学会了如何在实际中应用数据结构。
本次课程设计主要是拓扑排序的应用,我们根据问题描述给出了数据模型以及能够体现问题本身特点的逻辑结构。
在做程序之前,觉得教学计划编制这个问题,很难解决。
在通过我们一次次的画图,推算结果时,明白了该程序的主要思路。
在明白程序的实质后,开始选择数据的存储结构类型,最开始想到的是数组,但是用数组作为图的存储结构时,邻接矩阵可能是不对称的,没有多想就放弃了。
后来在查阅资料时,发现可以用邻接表作为图的存储结构,在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点。
确定了图的存储结构后,开始选择一种排序方法,通过上网查阅资料,发现拓扑排序可以很好的实现我们所需要的排序效果。
以前总是不清楚数据结构它有什么用途。
通过这此课程设计,明白我们所学的虽然只是课本知识,但很多时候,我们可以利用所学的来解决生活中碰到的一些问题。
同一个问题往往可以用不同的方法来解决。
无论我们学习什么课程,概念永远是基础,所有的知识都是建立在基础概念之上的。
数据结构包括线性结构、树形结构、图状结构或网状结构。
线性结构包括线性表、栈、队列、串、数组、广义表等,栈和队列是操作受限的线性表,串的数据对象约束为字符集,数组和广义表是对线性表的扩展:
表中的数据元素本身也是一个数据结构。
除了线性表以外,栈是重点,因为栈和递归紧密相连,递归是程序设计中很重要的一种工具。
树状结构中的重点自然是二叉树和huffman树。
对于二叉树的很多操作都是基于对二叉树的遍历,掌握了如何遍历。
huffman编码也有着很广泛的应用。
对于图状结构,主要学习图的存储结构及图的遍历。
对算法的学习是学习数据结构的关键。
要注重对算法的掌握。
对于一个算法,如果我们不是很理解的话,可以手动将算法走一遍,慢慢理解该算法的思想。
学习这门课程的最终目的,还是要学会如何设计算法,这需要我们长期的练习和思考。
参考文献
[1]严蔚敏,吴伟民.数据结构(c语言版).北京:
清华大学出版社,1997.4
[2]严蔚敏,吴伟民.数据结构题集(c语言版).北京:
清华大学出版社,2005
[3]谭浩强.C程序设计(第三版).北京:
附录源程序
源程序(附注释):
#include<
stdio.h>
stdlib.h>
math.h>
string.h>
conio.h>
ctype.h>
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineMAX_NAME3
#defineMAXCLASS100//顶点字符串的最大长度
#defineMAX_VERTEX_NUM100//最大顶点数
#defineN12
typedefcharVertexType[MAX_NAME];
intTotalTerms;
//学期总数
intMaxScores;
//学分上限
/*----图的邻接表存储表示----*/
voidprintf0()//界面
colorA"
\t***************************************************************\n"
\t★★\n"
\t★数据结构课程设计★\n"
\t★课题:
《教学计