数据结构课程设计之课程表实现Word文档下载推荐.docx
《数据结构课程设计之课程表实现Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计之课程表实现Word文档下载推荐.docx(32页珍藏版)》请在冰豆网上搜索。
4.2总体设计
1、说明本程序中用到的所有抽象数据类型的定义
ADTGraph{
数据对象V:
V是具有相同特性的数据元素的集合,称为顶点集.
数据关系R:
R={VR}
VR={(v,w)|v,w∈V,(v,w)表示v和w之间存在直接先修关系}
基本操作P:
voidCreatGraph(ALGraph*G)
操作结果:
创造图G
voidInitStack(SqSttack*S)
构造一个空栈S
voidStackEmpty(SqStack*S)
初始条件:
栈S已存在
若栈S为空栈,则返回TRUE,否则FALSE
voidPush(SqStack*S,inte)
插入元素e为新的栈顶元素
voidPop(SqStack*S,int*e)
栈S已存在且非空
删除S的栈顶元素,并用e返回其值
voidFindInDegree(ALGraphG,intindegree[])
拓扑排序完成
构造关键路径的先修关系网
voidTopologicalSort_1(ALGraphG,intnumterm,intuplcredit)
图G已存在
操作结构:
进行拓扑排序,并完成关系网的构造,使课程尽可能集中在前几个学期
voidTopologicalSort_2(ALGraphG,intnumterm,intuplcredit)
进行拓扑排序,并完成关系网的构造,使课程尽量均匀分布
}ADTGraph
2、说明主程序的流程
\
3、说明各程序模块之间的层次(调用)关系(图4.2-3)
4.3详细设计
1、实现概要设计中定义的所有数据类型,对每个操作只需要写出伪码算法
1)采用邻接表存储结构,构造没有相关信息的图G,并储存键入的相关信息
voidCreatGraph(ALGraph*G)
{通过循环语句完成对键入的课程名称,课程号,学分的存储,并课程先修关系建立邻接表
for(i=1;
i<
=G->
arcnum;
i++)/*构造顶点向量*/
{
printf("
\n请输入存在先修关系的两个课程的序号:
"
);
scanf(&
n,&
m);
while(课程号不在编入范围)
输入的顶点序号不正确请重新输入:
}
分配头结点的存储空间
if(p为空)
分配失败"
建立邻接表
printf("
建立的邻接表);
for(i=1;
i<
=G->
vexnum;
i++)
%d:
->
G->
vertices[i].classid);
for(p=G->
vertices[i].firstarc;
p!
=NULL;
p=p->
nextarc)
%d->
p->
adjvex);
NULL"
\n"
}
2)构造一个空栈S
voidInitStack(SqStack*S)
{赋予顺序栈足够的存储空间
if(!
S->
base)
{printf(存储分配失败)
exit
(1);
top=base初始栈为空,存储空间为所分配的足够的存储空间
3)判断是否为空栈
intStackEmpty(SqStack*S)
{if(栈S为空栈)
returnOK;
else
returnERROR;
4)入栈操作
voidPush(SqStack*S,inte)
{插入元素e为新的栈顶元素
if(栈满)
{为栈重新分配存储空间
if(!
printf(存储分配失败)
栈顶指针上移
5.取栈顶操作
intPop(SqStack*S,int*e)若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;
否则返回ERROR
{if(栈顶元素为空)exit
(1);
栈顶指针下移并将其值返回给*e
6)求图中各节点的入度
{
=G.vexnum;
i++)
indegree[i]=0;
while(G.vertices[i].firstarc)
indegree[G.vertices[i].firstarc->
adjvex]++;
G.vertices[i].firstarc=G.vertices[i].firstarc->
nextarc;
7)有向图G采用邻接表存储结构
{若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR。
intindegree[M];
存放各节点的入度
intcount;
课程编排数目计数器
intsumcredit;
每个学期的课程学分累加器
FindInDegree(G,indegree);
对各顶点求入度indegree[0..vernum-1]
G.vertices[i].indegree=indegree[i];
初始化栈
while(count!
=G.vexnum&
&
k<
=numterm)
sumcredit=0;
for(无先修的课程入栈)
if((G.vertices[i].indegree==0)&
(G.vertices[i].state==NOTSTUDY))
Push(&
S,i);
G.vertices[i].state=STUDY;
避免入度为零节点重复入栈
if(栈非空且学分计数器小于学分上限)
{
k=k+1;
第%d个学期学得课程有:
k);
for(i=1;
=G.vexnum;
i++)入度为零的节点入栈,即无先修的课程入栈
while(栈非空&
学分总数小于学分上限)
Pop(&
S,&
j);
sumcredit=sumcredit+G.vertices[j].credit;
if(学分计数器小于等于学分上限)
%s"
G.vertices[j].name);
课程数目累加
对j号顶点每个邻接点的入度减一
将未输出的节点重新压入栈
if(被编排课程<
编排课程总数)
printf(课程编排出错);
printf(课程编排成功);
8)有向图G采用邻接表存储结构若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR
头结点指针P
调用栈S
G.vertices[i].indegree=indegree[i];
InitStack(&
S);
课程编排计数器赋值为0
课程名计数器赋值
maxnum=G.vexnum/numterm+1;
sumnum=0;
i++)入度为零的节点入栈,即无先修的if((G.vertices[i].indegree==0)&
if(栈非空,学分计数器小于学分上限)
sumcredit=0;
Push(&
学分总数小于学分上限&
学期课程数目小于学期最大数目)
{出栈
积分器累加
sumnum=sumnum+1;
if((sumcredit<
=uplcredit)&
(sumnum<
=maxnum))
编排计数器累加
for(对j号顶点每个邻接点的入度减一)
G.vertices[p->
adjvex].indegree--;
elsePush(&
S,j);
if(课程未全部编排,有剩余)
printf(课程编排出错)
printf(课程编排成功)
2、对主程序和其它主要函数写出伪码算法
intmain()
intnumterm;
/*学期总数*/
intuplcredit;
/*一个学期的学分上限*/
intselectway;
scanf("
%d"
&
numterm);
输入学期总数
uplcredit);
输入一个学期的学分上限
选择编排策略:
1.课程尽可能集中到前几个学期;
2.课程尽量均匀分布"
if(选择1)
TopologicalSort_1(G,numterm,uplcredit);
if(选择2)
TopologicalSort_2(G,numterm,uplcredit);
return0;
3、画出函数的调用关系图(图4.3--03)
4.4测试与分析
4.4.1测试
学期总数:
6一学期的学分上限:
16该专业共开课程数目:
14
1.键入学期总数,学分上限,安排课程总数
2.输入课程名,课程号及相应学分
3.输入课程先修关系总数
4.顺序输入先修关系
5.输出邻接表
6.选择编排策略1,输出编排结果
7.选择编排策略2,输出编排结果
8.错误运行:
当输入两个相同课程号的不同课程,当输入先修顺序有环时…
9.运行结果:
4.4.2分析
1、调试过程中遇到的问题是如何解决的以及对设计与实现的回顾讨论和分析
调试过程中出现了很多问题,例如定义了无关变量、程序逻辑性错误等。
在种种错误下,自己根据提示修改了一部分简单错误。
对于其他错误,常常误认为是正确的,而不得改正。
无奈下求助同学帮助,在几个同课题同学帮助下,纠正了大多数问题。
其他几个复杂问题上网查阅资料,询问老师才最终解决。
设计两个不同拓扑的程序是遇到很多大麻烦,平时实验不涉及该内容,书上仅仅提供了一个算法。
在上网查阅资料,求助同学下才完成了框架。
面对程序考略不足,漏缺重要条件和关键步骤,遇到到了很大麻烦。
究其原因还是基础不牢,缺乏实验,动手能力差。
2、算法的时间复杂度和空间复杂度的分析
本程序算法的时间复杂度为O(n),空间复杂度为O(2n)
4.5附录
源程序代码及必要注释
/*Note:
YourchoiceisCIDE*/
#include"
stdio.h"
string.h"
malloc.h"
stdlib.h"
/*********图的邻接表存储表示*********/
#defineMAX_VERTEX_NUM100//最大课程总数
#defineSTACK_INIT_SIZE100//存储空间的初时分配量
#defineSTACKINCREMENT10//存储空间的分配增量
#defineOK1
#defineERROR0
#defineM100
#defineNOTSTUDY-1
#defineSTUDY1
typedefstructArcNode
intadjvex;
//该弧所指向的顶点的位置
structArcNode*nextarc;
//指向下一条弧的指针
}ArcNode;
typedefstructVNode
charname[30];
//课程名
intclassid;
//课程号
intcredit;
//课程的学分
intindegree;
//该结点的入度
intstate;
//该节点的状态
ArcNode*firstarc;
//第一个表结点的地址,指向第一条依附该顶点的弧的指针
}VNode,AdjList[100];
typedefintElemType;
typedefstruct
AdjListvertices;
intvexnum,arcnum;
//图的当前顶点数和弧数
}ALGraph;
ElemType*base;
//在栈构造之前和销毁之后,base的值为NULL
ElemType*top;
//栈顶指针
intstacksize;
//当前已分配的存储空间,以元素为单位
}SqStack;
//顺序栈
/*********图的构建*********/
voidCreatGraph(ALGraph*G)//采用邻接表存储结构,构造没有相关信息的图G,并储存键入的相关信息
{inti,m,n,f[100]={0};
ArcNode*p;
请输入需要编排课程总数:
G->
vexnum);
i++)//构造顶点向量
{printf("
请输入课程名\n"
%s"
vertices[i].name);
A:
请输入课程号\n"
if(f[G->
vertices[i].classid]){printf("
课程号重复,请重新输入\n"
gotoA;
elsef[G->
vertices[i].classid]=1;
请输入该课程的学分\n"
vertices[i].credit);
G->
vertices[i].indegree=G->
vertices[i].state=NOTSTUDY;
vertices[i].firstarc=NULL;
请输入课程先修关系总数:
arcnum);
请顺序输入每个课程先修关系(先修课程在前并以逗号作为间隔):
i++)//构造顶点向量
%d,%d"
while(n<
0||n>
vexnum||m<
0||m>
vexnum)
p=(ArcNode*)malloc(sizeof(ArcNode));
if(p==NULL)
memoryallocationfailed,goodbey"
p->
adjvex=m;
nextarc=G->
vertices[n].firstarc;
vertices[n].firstarc=p;
\n建立的邻接表为:
//输出建立好的邻接表
/********顺序栈的基本操作***********/
{//构造一个空栈S
S->
base=(int*)malloc(STACK_INIT_SIZE*sizeof(int));
{printf("
ERROR"
//存储分配失败
top=S->
base;
stacksize=STACK_INIT_SIZE;
//若栈S为空栈,则返回TRUE,否则返回FALSE
if(S->
top==S->
base)
/********入栈*********/
voidPush(SqStack*S,inte)
//插入元素e为新的栈顶元素
{
top-S->
base>
=S->
stacksize)
base=(int*)realloc(S->
base,(S->
stacksize+STACKINCREMENT)*sizeof(int));
top=S->
base+S->
stacksize;
stacksize+=STACKINCREMENT;
*S->
top++=e;
/*******出栈*******/
intPop(SqStack*S,int*e)
{//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;
否则返回ERROR
top==S->
base)exit
(1);
*e=*--S->
top;
/******寻找各节点入度******/
voidFindInDegree(ALGraphG,intindegree[])//求图中各节点的入度
inti;
/*****课程尽量集中到前几学期的拓扑排序*****/
{/*有向图G采用邻接表存储结构。
若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR。
*/
inti=0,j,k;
SqStackS;
//存放各节点的入度
int