如果一个有向图中没有包含简单的回路,这样的图为有向无环图。
图中的顶点代表事件(活动),图中的有向边说明了事件之间的先后关系。这种用顶点表示活动,用弧表示活动时间的优先关系的有向图称为顶点表示活动的网,简称AOV网(Active On Vertex Network)。
在AOV网中,若顶点u与顶点v之间存在一条有向边<u,v>,则说明事件u必须先于事件v完成。此处将u称为v的直接前驱,v称为u的直接后继。
对AOV网进行拓扑排序的方法和步骤如下:
(1)在有向图中找一个没有前驱(入度为0)的顶点并输出。
(2)在图中删除该顶点以及所有与该顶点出发的有向边。
(3)反复执行步骤(1)和步骤(2),直到所有顶点均被输出,或者AOV网中再也没有入度为0的顶点存在为止。
算法的两种结束情况:
(1)所有顶点全部输出,表明对该图的拓扑排序成功。
(2)图中有部分结点没有输出,但已经不存在入度为0的顶点,说明此AOV网中存在环。
直接输入(真的好麻烦,输错一个就要重来)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int M = 20;
typedef struct node
{
int adjvex;
struct node *next;
}edgenode;
typedef struct de //带顶点入度的头节点定义
{
edgenode *FirstEdge;
char vertex;
int id;//顶点的入度
}vertexnode;
typedef struct //AOV网的邻接表结构
{
vertexnode adjlist[M];
int n,e;
}AovGraph;
//创建AOV网络的邻接表
void creat(AovGraph *g)
{
int i,j,k;
edgenode *s;
printf("请输入点数和边数:");
scanf("%d%d",&g->n,&g->e);
getchar();
printf("\n请输入顶点序号以及该顶点入度:\n");
for(i=0;i<g->n;i++)
{
scanf("%c",&g->adjlist[i].vertex);
scanf("%d",&g->adjlist[i].id);
getchar();
g->adjlist[i].FirstEdge=NULL;
}
printf("\n请输入有向边:\n");
for(k=0;k<g->e;k++)
{
scanf("%d%d",&i,&j);
s=(edgenode*)malloc(sizeof(edgenode));
s->adjvex=j;
s->next=g->adjlist[i].FirstEdge;
g->adjlist[i].FirstEdge=s;
}
}
//打印AOV网络的邻接表
void print(AovGraph g)
{
int i,j,k;
edgenode *p;
for(i=0;i<g.n;i++)
{
printf("入度:%d 地址:%d char值:C%c-> ",g.adjlist[i].id,i,g.adjlist[i].vertex);
p=g.adjlist[i].FirstEdge;
if(p == NULL)
{
printf("NULL\n");
continue;
}
while(p)
{
printf("%d",p->adjvex);
if(p->next)
{
printf(" -> ");
}
p=p->next;
}
printf("\n");
}
return ;
}
//拓扑排序算法
int TopSort(AovGraph g)
{
int k=0,i,j,v,flag[M];
int queue[M];
int front ,rear;
edgenode *p;
front = 0;
rear = 0;
memset(flag,0,sizeof(flag));//访问标记初始化
for(i=0;i<g.n;i++)
{
if(g.adjlist[i].id==0 && flag[i]==0)
{
queue[rear++]=i;
flag[i]=1;
}
}
printf("\nAOV网的拓扑排序为:\n");
while(front < rear)//当队列空间不为空时
{
v = queue[front++];//队首元素出队
printf("%c ",g.adjlist[v].vertex);
k++;//计数器加一
p=g.adjlist[v].FirstEdge;
while(p)//将所有与v邻接的顶点的入度减一
{
j=p->adjvex;
if(--g.adjlist[j].id==0 && flag[j]==0)
{
queue[rear++]=j;
flag[j]=1;
}
p=p->next;
}
}
return k;
}
int main ()
{
int node_num;
AovGraph g;
creat(&g);
print(g);
node_num=TopSort(g);
printf("\n一共输出%d个结点\n",node_num);
if(g.n==node_num)
printf("所有顶点全部输出,对该图拓扑排序成功!\n");
else
printf("此AOV网中存在着环,无法完成拓扑排序!\n");
return 0;
}
使用文件读取数据(十分方便)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int M = 20;
typedef struct node
{
int adjvex;
struct node *next;
}edgenode;
typedef struct de //带顶点入度的头节点定义
{
edgenode *FirstEdge;
char vertex;
int id;//顶点的入度
}vertexnode;
typedef struct //AOV网的邻接表结构
{
vertexnode adjlist[M];
int n,e;
}AovGraph;
//创建AOV网络的邻接表
void creat(AovGraph *g)
{
int i,j,k;
edgenode *s;
FILE *f;
f=fopen("test.txt","r");
if(f)
{
fscanf(f,"%d%d",&g->n,&g->e);
for(i=0;i<g->n;i++)
{
fscanf(f,"%1s %d",&g->adjlist[i].vertex,&g->adjlist[i].id);
g->adjlist[i].FirstEdge=NULL;
}
for(k=0;k<g->e;k++)
{
fscanf(f,"%d%d",&i,&j);
s=(edgenode*)malloc(sizeof(edgenode));
s->adjvex=j;
s->next=g->adjlist[i].FirstEdge;
g->adjlist[i].FirstEdge=s;
}
fclose(f);
}
else
{
g->n=0;
}
}
//打印AOV网络的邻接表
void print(AovGraph g)
{
int i,j,k;
edgenode *p;
for(i=0;i<g.n;i++)
{
printf("入度:%d 地址:%d char值:C%c-> ",g.adjlist[i].id,i,g.adjlist[i].vertex);
p=g.adjlist[i].FirstEdge;
if(p == NULL)
{
printf("NULL\n");
continue;
}
while(p)
{
printf("%d",p->adjvex);
if(p->next)
{
printf(" -> ");
}
p=p->next;
}
printf("\n");
}
return ;
}
//拓扑排序算法
int TopSort(AovGraph g)
{
int k=0,i,j,v,flag[M];
int queue[M];
int front ,rear;
edgenode *p;
front = 0;
rear = 0;
memset(flag,0,sizeof(flag));//访问标记初始化
for(i=0;i<g.n;i++)
{
if(g.adjlist[i].id==0 && flag[i]==0)
{
queue[rear++]=i;
flag[i]=1;
}
}
printf("\nAOV网的拓扑排序为:\n");
while(front < rear)//当队列空间不为空时
{
v = queue[front++];//队首元素出队
printf("%c ",g.adjlist[v].vertex);
k++;//计数器加一
p=g.adjlist[v].FirstEdge;
while(p)//将所有与v邻接的顶点的入度减一
{
j=p->adjvex;
if(--g.adjlist[j].id==0 && flag[j]==0)
{
queue[rear++]=j;
flag[j]=1;
}
p=p->next;
}
}
return k;
}
int main ()
{
int node_num;
AovGraph g;
creat(&g);
print(g);
node_num=TopSort(g);
printf("\n一共输出%d个结点\n",node_num);
if(g.n==node_num)
printf("所有顶点全部输出,对该图拓扑排序成功!\n");
else
printf("此AOV网中存在着环,无法完成拓扑排序!\n");
return 0;
}