- 什么是拓扑排序
对一个
有向无环图G
进行拓扑排序
,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
- 背景知识
一个
较大的工程
往往被划分成许多子工程
,我们把这些子工程称作活动
。在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动
(子工程),图中的有向边代表活动的先后关系
,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行
。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网
(Activity On Vertex network),简称AOV网。
算法大致思想
由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。
- 选择一个入度为0的顶点并输出之;
- 从网中删除此顶点及所有出边。
- 循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列
c/c++代码实现
#include <iostream>
#include<stdlib.h>
#define maxSize 100
typedef struct EdgeNode{//边结点
int adjvex;
struct EdgeNode* next;
}EdgeNode;
typedef struct Vnode{//顶点结点
int data;
int in;//新增的入度个数
EdgeNode *firstEdge;
}Vnode,Adjvex[maxSize];
typedef struct AGraph{//图结点
Adjvex adjvex;
int n,e;
}AGraph;
void createGraph(AGraph &G){//邻接表创建图
EdgeNode *p;
int i,j,k;
printf("请输入图的顶点数和边数\n");
scanf("%d %d",&G.n,&G.e);
printf("请输入图的顶点\n");
for(i=0;i<G.n;i++){//输入图的顶点
scanf("%d",&G.adjvex[i]);
G.adjvex[i].firstEdge=NULL;
G.adjvex[i].in=0;//所有的顶点入度初始化为0
}
printf("请输入边的下标i j\n");
for(k=0;k<G.e;k++){//输入图的边
scanf("%d %d",&i,&j);
p=(EdgeNode *)malloc(sizeof(EdgeNode));
p->adjvex=j;
p->next=G.adjvex[i].firstEdge;
G.adjvex[i].firstEdge=p;
G.adjvex[j].in++; //j顶点入度自增长
}
}
int topSort(AGraph G){//拓扑排序
EdgeNode *p;
int i,j,k,count=0;
int *que;//栈里面存放的是顶点下标
que=(int *)malloc(G.n*sizeof(int));
int top=-1;//创建并初始化栈
for(i=0;i<G.n;i++){
if(!G.adjvex[i].in){//若入度为0的,则入栈
que[++top]=i;
}
}
while(top!=-1){//若栈不为空
k=que[top--];//栈顶出栈
printf("%d ",G.adjvex[k].data);
count++;//计数访问了多少顶点
for(p=G.adjvex[k].firstEdge;p!=NULL;p=p->next){//遍历出栈顶点的边表
G.adjvex[p->adjvex].in--;//与之相邻接的顶点的入度自减
if(G.adjvex[p->adjvex].in==0){//把自减后入度为0的顶点入栈
que[++top]=p->adjvex;
}
}
}
if(count<G.n){//若有顶点未访问到,则拓扑排序失败
return 0;
}else{
return 1;
}
}
int main(int argc, char** argv) {
AGraph G;
createGraph(G);
topSort(G);
return 0;
}