拓扑排序1
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//--------------------初始化图 void GAdjoin::InitAdjoin() {
int v,e; cout<<endl; cout<<"请输入顶点数:"; cin>>v; VertexNum=v; cout<<endl; for(int i=0;i<=v;i++) {
第三部分,主函数,先后调用 void CreatGraph(ALGraph *G)函数构建图、 void TopologicalSort(ALGraph *G)函数输出拓扑排序实现整个程序。 3.设计的主程序流程(见附页)
三 详Leabharlann Baidu设计
(实现概要设计中定义的所有数据类型,对每个操作写出伪码算法;对主 程序和其他模块也都需要写出伪码算法(伪码算法达到的详细程度建议为;按照 伪码算法可以在计算机键盘直接输入高级程序设计语言程序);写出出函数和过 程的调用关系。)
}
//---------------创建图的邻接表 void GAdjoin::CreateAdjoin() {
int fromvex,endvex,e; cout<<endl; for(e=0;e<EdgeNum;e++){
cout<<"请输入第"<<e+1<<"条边(两端点序号,空格开):"; cin>>fromvex>>endvex; p=new edgenode; p->adjvex=endvex; p->next=adjlist[fromvex]; adjlist[fromvex]=p; } }
1.实现概要设计中定义的所有数据类型
#include<iostream> #include<iomanip> using namespace std;
struct edgenode //------邻接表中的边节点类型 {
int adjvex; edgenode *next; };
class GAdjoin { public:
2.3 void Push(SqStack *S,ElemType e) 进栈操作,插入元素 e 为新的栈顶元素。
2.4 int StackEmpty(SqStack *S) 判断栈是否为空,语句 if (S->top=S->base )判断,若栈不为空,则删除 S 的
栈顶元素,并返回 OK;否则返回 ERROR。 2.5 void CreatGraph (ALGraph *G)
void InitAdjoin();//--------------------初始化图 void CreateAdjoin();//---------------创建图的邻接表 void PrintAdjoin();//-------------输出图的邻接表 void Toposort(); //------------输出图的拓扑序列 private: int MaxValue; int VertexNum; int EdgeNum; bool visited[50]; edgenode* adjlist[50]; edgenode*p; };
数据结构课程设计
2010— 2011 学年第 二 学期
课程名称 设计题目 学生姓名 学号 专业班级 指导教师
数据结构课程设计 拓扑排序 黄亮亮
200910510219 09 计科(2) 李娟 徐星
2011 年 7 月 5 日
一 需求分析 1.问题描述
本次课程设计题目是:用邻接表构造图 然后进行拓扑排序,输出拓扑排序 序列
五 总结 拓扑排序就是对一个有向无环图(Directed Acyclic Graph 简称 DAG)G 进行拓扑排序,是
将 G 中所有顶点排成一个线性序列,使得图中任意一对顶点 u 和 v,若<u,v> ∈E(G),则 u 在线性序列中出现在 v 之前。
在进行课程设计中,更好的认识了拓扑排序。理清了各个模块之间算法之间的条理。认 识了 伪代码(Pseudocode)是一种算法描述语言。使用伪代码的目的是为了使被描 述 的 算 法 可 以 容 易 地 以 任 何 一 种 编 程 语 言( Pascal ,C,Java ,etc )实 现 。因 此 ,伪 代 码必须结构清晰、代码简单、可读性好,并且类似自然语言。 介于自然语言与编程 语 言 之 间 。它 是 一 种 让 人 便 于 理 解 的 代 码 。不 依 赖 于 语 言 的 ,用 来 表 示 程 序 执 行 过 程 , 而不一定能编译运行的代码。在数据结构讲算法的时候用的很多。
2.各程序模块之间的层次调用关系 第一部分,void CreatGraph(ALGraph *G)函数构建图,用邻接表存储。这个
函数没有调用函数。 第二部分,void TopologicalSort(ALGraph *G)输出拓扑排序函数,这个函数
首先调用 FindInDegree(G,indegree)对各顶点求入度 indegree[0……vernum-1];然 后设置了一个辅助栈,调用 InitStack(&S)初始化栈,在调用 Push(&S,i)入度为 0 者进栈,while(!StackEmpty(&S))栈不为空时,调用 Pop(&sS,&n)输出栈中顶点并 将以该顶点为起点的边删除,入度 indegree[k]--,当输出某一入度为 0 的顶点时, 便将它从栈中删除。
adjlist[i]=NULL; } cout<<"请输入边数:"; cin>>e; EdgeNum=e;
} 2.算法和各模块的代码
程序中各函数算法思想如下:
2.1 void InitStack(SqStack *S) 初始化栈将栈的空间设为 STACK-INIT-SIZE。
2.2 int Pop(SqStack *S,ElemType *e) 出栈操作,若站不空,删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否 则返回 ERROR。
首先输出建立的邻接表,然后是最终各顶点的出度数,再是拓扑排序的序 列,并且每输出一个顶点,就会输出一次各顶点的入度数。
(3) 程序所能达到的功能; 因为该程序是求拓扑排序,所以算法的功能就是要输出拓扑排序的序列,
在一个有向图中,若用顶点表示活动,有向边就表示活动间先后顺序,那么输出 的拓扑序列就表示各顶点间的关系为反映出各点的存储结构,以邻接表存储并输 出各顶点的入度。
构建图,用邻接表存储,首先定义邻接表指针变量,输入顶点数和弧数,
初始化邻接表,将表头向量域置空,输入存在弧的点集合,当输入顶点值超出输
入值的范围就会出错,否则依次插入进邻接表,最后输出建立好的邻接表。
2.6 void FindInDegree(ALGrap G, int indegreee[]) 求入度操作,设一个存放各顶点入度的数组 indegreee[],然后
int adjvex; edgenode *next;
};
class GAdjoin { public:
void InitAdjoin();//--------------------初始化图 void CreateAdjoin();//---------------创建图的邻接表 void PrintAdjoin();//-------------输出图的邻接表 void Toposort(); //------------输出图的拓扑序列 private: int MaxValue; int VertexNum; int EdgeNum; bool visited[50]; edgenode* adjlist[50]; edgenode*p; };
拓扑排序实际是对邻接表表示的图 G 进行遍历的过程,每次访问一个入度 为零的顶点,若图 G 中没有回路,则需扫描邻接表中的所有边结点,在算法开 始时,为建立入度数组 D 需访问表头向量中的所有边结点,算法的时间复杂度 为 O(n+e)。 四 测试与分析
对有向无环图【下图】进行拓扑排序。
输入:
结果如下:
二 概要设计 1. 算法中用到的所有各种数据类型的定义
在该程序中用邻接表作为图的存储结构。首先,定义表结点和头结点的结构 类型,然后定义图的结构类型。创建图用邻接表存储的函数,其中根据要求输入 图的顶点和边数,并根据要求设定每条边的起始位置,构建邻接表依次将顶点插 入到邻接表中。 拓扑排序的函数在该函数中首先要对各顶点求入度,其中要用到求入度的函数, 为了避免重复检测入度为零的顶点,设置一个辅助栈,因此要定义顺序栈类型, 以及栈的函数:入栈,出栈,判断栈是否为空。
FindInDegree( G, indegreee[])对各顶点求入度;为了避免重复检测入度为零 0 的
顶点,设置一个栈,调用 InitStack(&S)初始化栈,在调用 Push(&S,i)入度为 0 者 进栈,while(!StackEmpty(&S))栈不为空时,调用 Pop(&sS,&n)输出栈中顶点并将 以该顶点为起点的边删除,入度 indegree[k]--,当输出某一入度为 0 的顶点时,便 将它从栈中删除。 3.算法的时间复杂度和空间复杂度
拓扑排序的基本思想为: 1).从有向图中选一个无前驱的顶点输出; 2).将此顶点和以它为起点的弧删除; 3). 重复 1),2)直到不存在无前驱的顶点; 4). 若此时输出的顶点数小于有向图中的顶点数,则说明有向图中存在回 路,否则输出的顶点的顺序即为一个拓扑序列。 2.基于邻接表的存储结构 入度为零的顶点即为没有前驱的顶点, 我们可以附设一个存放各顶点入度 的数组 indegree[ ],于是有 (1)找 G 中无前驱的顶点——查找 indegree[i]为零的顶点 vi; (2)删除以 i 为起点的所有弧——对链在顶点 i 后面的所有邻接顶点 k,将 对应的 indegree[k] 减 1。
//-------------输出图的邻接表 void GAdjoin::PrintAdjoin() {
for(int i=0;i<VertexNum;i++){ cout<<'v'<<i; p=adjlist[i]; while(p!=NULL){ cout<<"->"<<p->adjvex; p=p->next; }
//--------------------初始化图 void GAdjoin::InitAdjoin() {
int v,e; cout<<endl; cout<<"请输入顶点数:"; cin>>v; VertexNum=v; cout<<endl; for(int i=0;i<=v;i++) {
adjlist[i]=NULL; } cout<<"请输入边数:"; cin>>e; EdgeNum=e;
在设计中,我们遇到了程序正确,却对某些无向图无法进行拓扑排序的问题。多 次 对 程 序 进 行 修 改 后 ,才 可 以 进 行 拓 扑 排 序 。问 题 出 在 调 用 函 数 的 错 误 理 解 ,模 块 之 间的联系模糊不清。
六附录: 源程序清单
#include<iostream> #include<iomanip> using namespace std; struct edgenode //------邻接表中的边节点类型 {
indegreee[i]=0 赋初值,for 循环 indegreee[]++,存储入度数。 2.7 void TopologicalISort(ALGraph G)
输出拓扑排序函数。其思路是若 G 无回路,则输出 G 的顶点的一个拓扑序 列并返回 OK,否则返回 ERROR。首先由于邻接表的存储结构入度为零的顶点 即为没有前驱的顶点,我们可以附设一个存放个顶点入度的数组,调用
为了避免重复检测入度为零的顶点,可以再设置一个辅助栈,若某一顶点 的入度减为 0,则将它入栈。每当输出某一入度为 0 的顶点时,便将它从栈中删 除。 3 基本要求
(1) 输入的形式和输入值的范围; 首先是输入要排序的顶点数和弧数,都为整型,中间用分隔符隔开;再输
入各顶点的值,为正型,中间用分隔符隔开;然后输入各条弧的两个顶点值, 先输入弧头,再输入弧尾,中间用分隔符隔开,输入的值只能是开始输入的顶 点值否则系统会提示输入的值的顶点值不正确,请重新输入,只要继续输入正 确的值就行。 (2) 输出的形式;