1、 .正常的输入输入:输入课程总数:3请输入课程1的名称:小学数学请输入课程2的名称:初中数学请输入课程3的名称:大学数学小学数学是否有先修(1/0):初中数学是否有先修(1/0):1请输入先修课程的名称:高中数学是否有先修(1/0):输出: 小学数学 初中数学 高中数学 .正常的输入42请输入课程4的名称: 1是否有先修(1/0):2是否有先修(1/0):3是否有先修(1/0):4是否有先修(1/0):4 1 3 2有两个先修课程的情况ABCD A是否有先修(1/0):B是否有先修(1/0):C是否有先修(1/0):D是否有先修(1/0):A B C D有三个先修课程的情况D A B C所有课
2、程无先修1 2 3 二、概要设计1.抽象数据类型 题设要求使用一个有向图表示教学计划,顶点表示某门课程,有向边表示课程之间的先修关系,数据的对象是图中的每一个顶点和有向边。由此为本问题确定一个图的数据关系。 本题目需要一个数据结构来储存遍历过的图的结点,该数据结构满足先进先出,所以用队列来实现。2.ADTADT Edge数据对象: N(边的名称) V(标记) F(先修课结点)数据关系:(N&V&F)R (R1&R2&Rn)Graph基本操作: string getVal(int v)/返回边的名称 int getMark(int v)/返回标记 void setVal(int v, strin
3、g val)/设边的名称 void setMark(int v, int Mark)/设置标记 void setfirst(int v)/设置先修结点标记ADT GraphV,R(分别代表某门课程的顶点组成的一个顶点集V和代表课程先修关系 的有向弧边组成的一个弧集R。)VR| v,wV 且 P(v,w)表示从 v 到 w 的一条弧,并称 v 为弧头,w 为弧尾。 int n(); /返回图中的顶点数 int first(int); /返回该点的第一条邻边 int next(int); /返回该店的下一条邻边 void setEdge(int,int,int); /为有向边设置权值 void F
4、ind(string search, int& v) int n()ADT queue 前指针front,后指针rearR=|ai-1,aicar,i=1,2,3.n约定a1 为队列头,an为队列尾。queue(); /队列结构初始化queue(); /结构销毁操作bool push(const int& it); /数据入列bool pop(int& /数据出列int size(); /获取队列长度3.算法的基本思想通过用户输入的顶点的个数(课程数)初始化一个表示有向图的相邻矩阵,初始化边的访问次数全部设置为零,通过输入边的信息和先修关系,设置先修关系的计数器,记录每条边先修关系的数量,完成
5、对有项图的构建。将先修关系为零的边放入队列,然后开始处理队列。当从队列中删除一个顶点时,把它打印出来,同时将其所有相邻顶点的先修关系计数器减一。当某个相邻顶点的计数器为0时,就将其放入队列。如果还有顶点未被打印,而队列已经为空,则图中必然包含回路(既不可能不违反先决条件完成任务)。4.程序的流程 (1) 初始化模块:输入课程总数,再输入相应数量的课程编号及每个课程的先修课程,用这些信息初始化一个有向图。(2) 拓扑排序模块:对有向图进行拓扑排序。(3) 输出模块:根据有向图是否为空输出。为空时,输出拓扑排序结果;不为空时输出输入错误提示。三、详细设计1.物理数据类型用户输入的课程个数不定,所以
6、存储拓扑排序后的顶点的个数不定,对于图有两种存储方式,本题中用邻接矩阵来存储图的信息,对于边很少的图来说,虽然用邻接矩阵有些浪费空间,但是题目做起来相对方便。由于用户输入的课程个数不定,使用链式栈。使用string类型储存用户信息和边的信息。2.算法的具体步骤 初始化一个有向图先修信息的储存拓扑排序与输出初始化一个有向图:包括初始化被访问标记和先修标记,动态创建二维数组和用于储存边信息的一维数组。 Graph(int numVert) int i, j; numVertex = numVert; numEdge = 0; mark = new PointnumVert; / Initializ
7、e mark array for (i = 0; i numVertex; i+) marki.visit = -1;/包括初始化被访问标记和先修标记 marki.first = 0; matrix = (int*) new int*numVertex; / Make matrix matrixi = new intnumVertex; i+)/Edges start w/0 weight for (int j = 0; j j+) matrixij = 0; .先修信息的存储:由用户输入是否有先修课程后,用户每输入一个先修课程,就将这个课程对应的先修标记加1. cout a.getVal(i
8、) judge; if (judge) a.setfirst(i); cout Ch1; a.Find(Ch1, v1); a.setEdge(v1, i, 10); void setfirst(int v) markv.first+;拓扑排序与输出:定义两个队列A和 B,将先修关系为零的边放入队列A,然后开始处理队列。当从队列A中删除一个顶点时,该顶点进入B队列,再把该顶点打印出来,同时将其所有相邻顶点的先修关系计数器减一。重复将队列B中首元素输出并删除,直到队列为空,就是课程表的排序。void DFS(Graph* G, queue *Q, queue *L) for (int v = 0
9、; v push(v); setMark(v, 1); while (Q-size() != 0) int i = Q-front();/获取Q栈首元素pop();/弹出Q栈 L-push(i);/进L栈 for (int w = first(i); w push(w); setMark(w, 1); for (int i = 0; if (getMark(i) = -1) /为0时表示还未被删除,图不为空课程输入错误! endl; exit(0); 3.算法的时空分析及改进设想因为图的邻接矩阵是一个|V|V|矩阵,所以邻接矩阵的空间代价为(|V|2),对于有n个顶点的和E条弧的有向图而言,对
10、此图的拓扑排序算法时间复杂度为(V+E) 4.输入和输出的格式 1.输入课程数ncout n;if (n cout 输入错误重新输入(大于零的整数)2.输入每门课的课程编号for (int i = 0;请输入课程 i + 1 名称: Ch; a.setVal(i, Ch); 3. 获得先修的课程编号 judge = 0;1. 编制成功,把队列S中的顶点序列输出。 cout 课程表的排序为: a.DFS(&a, &Q, &L); int j = L.front(); a.getVal(j) L.pop();2. 编制失败,图中有回路,输出错误信息,结束程序。if(G.getMark(i)=0)
11、/为0时表示该顶点未经过拓扑排序 coutendl; exit(0);四调试分析 DFS问题,书上思路很明确并且有很多源码,没有大的问题。五测试结果1.正常的输入输出3.有两个先修课程的情况附录#includequeuefstreamstringiomanipusing namespace std;class Pointpublic: string LessonName; int visit; int first;/1有先修,0无;class Graph/Implement adjacency matrixprivate: int numVertex, numEdge;/Store numbe
12、r of vertices edges int *matrix; / Pointer to adjacency matrix Point *mark; / Pointer to mark array Graph(int numVert) / Make graph w/ numVert vertices Graph() delete mark; delete matrixi; delete matrix; return numVertex; int e() return numEdge; int first(int v) / Return vs first neighbor int i; if
13、(matrixvi != 0 & marki.visit = -1) return i; return i; / Return n if none int next(int v1, int v2) / Get v1s neighbor after v2 for (i = v2 + 1; if (matrixv1i ! marki.visit = -1) /cout此时next的i值是:v1+1i+1 return i; / Set edge (v1, v2) to wgt void setEdge(int v1, int v2, int wgt) numEdge+;/ERROR matrixv
14、1v2 = wgt; void delEdge(int v1, int v2) / Delete edge (v1, v2) if (matrixv1v2 ! numEdge-; matrixv1v2 = 0; int weight(int v1, int v2) return matrixv1v2; string getVal(int v) return markv.LessonName; int getMark(int v) return markv.visit; void setVal(int v, string val) markv.LessonName = val; void setMark(int v, int Mark) markv.visit = Mark; if (marki.LessonName = search) v = i; return;路径错误 return; void DFS(Graph* G, queue int main() int n; int v1; int v2; int judge; string Ch; string Ch1; string Ch2; queue Q; L; int D100; int count = 0; if (n Graph a(n); system(pause); return 0;