任务描述
本关任务:AOV网的存储结构为邻接表,要求编写函数实现AOV网的拓扑排序算法。
相关知识
拓扑排序基本概念
设G=(V,E)
是一个具有n
个顶点的有向图,图中用顶点表示活动,用边表示活动之间的优先关系,这样的有向图称为用顶点表示活动的网,简称AOV(Activity On vertex Network)网。
该网中顶点序列v1、v2、…、vn
称为一个拓扑序列,当且仅当该顶点序列满足下列条件: 若<vi,vj>
是图中的边(即从顶点vi
到顶点vj
有一条路径),则在序列中顶点vi
必须排在顶点vj
之前。
在一个有向图中找一个拓扑序列的过程称为拓扑排序。
例如,计算机专业的学生必须完成一系列规定的基础课和专业课才能毕业,假设这些课程的名称与相应编号如下表所示。
课程代号 | 课程名称 | 先修课 |
---|---|---|
C1 | 高等数学 | 无 |
C2 | 程序设计 | 无 |
C3 | 离散数学 | C1 |
C4 | 数据结构 | C2,C3 |
C5 | 编译原理 | C2,C4 |
C6 | 操作系统 | C4,C7 |
C7 | 计算机组成原理 | C2 |
对这个有向图进行拓扑排序可得到拓扑序列:
拓扑排序算法思想
(1)从AOV网中选择一个没有前驱(即入度为0)的顶点并且输出它。 (2)从AOV网中删去该顶点,并且删去从该顶点发出的全部有向边。 (3)重复上述两步,直到剩余的网中不再存在没有前驱的顶点为止。
对任一有向图进行拓扑排序有两种结果:
-
图中全部顶点都包含在拓扑序列中,这说明该图中不存在回路;
-
图中部分顶点未被包含在拓扑序列中,这说明该图中存在回路。
所以可以采用拓扑排序判断一个有向图中是否存在回路,如果此有向图没有回路,则此有向图为AOV网。
不论图的存储结构为邻接矩阵还是邻接表,拓扑排序算法思想是一致的,只是计算图G每个顶点的入度过程中具体操作不同。
用邻接矩阵存储图时,定义函数计算图G每个顶点的入度,并且保存在indegree数组:
void FindInDegree(MGraph G,int indegree[])
{ //计算图G每个顶点的入度,并且保存在indegree数组
int i,j;
for(i=0;i<G.vexnum;i++)
indegree[i]=0; /* 赋初值 */
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++)
if( G.arcs [j][i].adj == 1)
indegree[i]++;
}
用邻接表存储图时,定义函数计算图G每个顶点的入度,并且保存在indegree数组:
void FindInDegree(ALGraph G,int indegree[])
{ //计算图G每个顶点的入度,并且保存在indegree数组
int i;
ArcNode *p;
for(i=0;i<G.vexnum;i++)
indegree[i]=0; /* 赋初值 */
for(i=0;i<G.vexnum;i++)
{
p=G.vertices[i].firstarc;
while(p)
{
indegree[p->data.adjvex]++;
p=p->nextarc;
}
}
}
编程要求
有向图的存储结构为邻接表,编写函数实现图的拓扑排序算法:
- int TopologicalSort(ALGraph G);// 有向图G采用邻接表存储结构。若G无回路,则输出G的顶点的一个拓扑序列并返回1,否则返回0
如果此有向图没有回路,则此有向图为AOV网。
测试说明
平台会对你编写的代码进行测试:
测试输入: 0
lt6.txt
输入说明: 第一行输入
0
,表示输入图的类型为有向图。 第二行输入文件名,该文件里保存了图的数据信息,内容如下: 7 7 高等数学 程序设计 离散数学 数据结构 编译原理 操作系统 计算机组成原理 高等数学 离散数学 离散数学 数据结构 数据结构 操作系统 数据结构 编译原理 程序设计 计算机组成原理 程序设计 编译原理 计算机组成原理 操作系统
第1行为图的顶点的个数n; 第2行为图的边的条数m; 第3行至第n+2行是n个顶点的数据; 第n+3行至第n+m+2行是m条边的数据;
预期输出: 有向图
7个顶点:
高等数学 程序设计 离散数学 数据结构 编译原理 操作系统 计算机组成原理
7条弧(边):
高等数学→离散数学
程序设计→编译原理 程序设计→计算机组成原理
离散数学→数据结构
数据结构→编译原理 数据结构→操作系统
计算机组成原理→操作系统
输出有向图g的拓扑序列:
程序设计 计算机组成原理 高等数学 离散数学 数据结构 操作系统 编译原理
输出说明: 第一行输出图的类型。 第二部分起输出图的顶点和边的数据信息。 第三部分输出有向图的一个拓扑序列,若有回路,则输出提示此有向图有回路。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include<iostream>
using namespace std;
#define INFINITY 4270000 // 用整型最大值代替∞
#include"ALGraph.h"
#include"sqstack.h"
void FindInDegree(ALGraph G,int indegree[]); // 求顶点的入度
int TopologicalSort(ALGraph G);// 有向图G采用邻接表存储结构。若G无回路,则输出G的顶点的一个拓扑序列并返回1,否则返回0
int main()
{
ALGraph g;
CreateGraphF(g); // 利用数据文件创建无向图
Display(g); // 输出无向图
printf("输出有向图g的拓扑序列:\n");
TopologicalSort(g); // 输出有向图f的拓扑序列
return 0;
}
void FindInDegree(ALGraph G,int indegree[])
{ //计算图G每个顶点的入度,并且保存在indegree数组
int i;
ArcNode *p;
for(i=0;i<G.vexnum;i++)
indegree[i]=0; /* 赋初值 */
for(i=0;i<G.vexnum;i++)
{
p=G.vertices[i].firstarc;
while(p)
{
indegree[p->data.adjvex]++;
p=p->nextarc;
}
}
}
int TopologicalSort(ALGraph G)
{ // 有向图G采用邻接表存储结构。
// 若G无回路,则输出G的顶点的一个拓扑序列并返回1,否则返回0。
/********** Begin **********/
int i,k,count=0;
int indegree[MAX_VERTEX_NUM];
SqStack S;
ArcNode *p;
FindInDegree(G,indegree);
InitStack(S);
for(i=0;i<G.vexnum;++i)
if(!indegree[i])
Push(S,i);
while(!StackEmpty(S)){
Pop(S,i);
printf("%s ",G.vertices[i].data);
++count;
for(p=G.vertices[i].firstarc;p;p=p->nextarc){
k=p->data.adjvex;
if(!(--indegree[k]))
Push(S,k);
}
}
if(count<G.vexnum){
printf("\n此有向图有回路\n");
return 0;
}
else
return 1;
/********** End **********/
}