AOV网介绍
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称AOV网(Activity On Vertex Network).
如图:
设G(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,…vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在顶点vj之间。则我们称这样的顶点序列为一个拓扑序列。
拓扑排序
拓扑排序,就是对一个有向图构造拓扑序列的过程。
构造时,会出现两种结果
- 如果此网的全部顶点都被输出,则说明它是不存在环(回路)的AOV网;
- 如果输出定点数少了,哪怕少了一个,也说明这个网存在回路,不是AOV网。
拓扑排序算法
对AOV网构建拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点输出,然后删除此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
拓扑排序适用的数据结构:邻接表(便于删除节点)
in存放入度,data存放数据,firstedge指向下一个元素
举栗
如图,给出一张AOV图
它的邻接表结构
先来看邻接矩阵的结构代码:
/*邻接矩阵结构*/
typedef struct
{
VertexType vexs[MAXVEX]; /*vertex*/
int arc[MAXVEX][MAXVEX]; /*邻接矩阵*/
int numVertexes, numEdges; /*顶点个数,边个数*/
} MGraph;
再来看邻接表的结构代码:
//邻接表结构
typedef struct EdgeNode /*边表节点*/
{
int adjvex; /*邻接点域,存储该顶点对应的下标*/
int weight; //用于存储权值,非网图可不需要
struct EdgeNode *next; //链域,指向下一个邻接点
} EdgeNode;
typedef struct VertexNode //定点表结点
{
int in; //顶点入度
char data; //顶点域,存储顶点信息
EdgeNode *firstedge; //边表头指针
} VertexNode, AdjList[MAXVEX];
typedef struct
{
AdjList adjList;
int numVertexes, numEdges; //图中当前顶点数和边数
} graphAdjList, *GraphAdjList;
为了实现删除入度为0的顶点,我们同时需要辅助数据结构——栈。
以下为拓扑排序的代码实现:
//拓扑排序,有环返回0,无环返回1并输出序列
Status TopologicalSort(GraphAdjList GL)
{
EdgeNode *e;
int i, k;
char gettop;
int top = 0; //用于栈指针下标
int count = 0; //用于统计输出顶点的个数
char *stack; //建立栈将入度为0的顶点入栈
stack = (char *)malloc(GL->numVertexes * sizeof(char));//为栈分配内存空间
for (i = 0; i < GL->numVertexes; i++)
if (0 == GL->adjList[i].in)
stack[++top] = vexs1[i]; //入度为0 的顶点入栈
int index;
while (top != 0)
{
gettop = stack[top--];
for (int kk = 0; kk < MAXVEX; kk++)
if (vexs1[kk] == gettop)
index = kk;
printf("%c -> ", GL->adjList[index].data);
count++; //输出i顶点,并计数
for (e = GL->adjList[find_index(gettop)].firstedge; e; e = e->next)
{
k = e->adjvex;
if (!(--GL->adjList[k].in)) /*将i顶点的邻接点的入度减一,如果减一后等于0,则入栈*/
stack[++top] = vexs1[k];
}
}
printf("\n");
if (count < GL->numVertexes)
return ERROR;
else
return OK;
}
测试数据:
// G->arc[0][4] = 1;
// G->arc[0][5] = 1;
// G->arc[0][11] = 1;
// G->arc[1][2] = 1;
// G->arc[1][4] = 1;
// G->arc[1][8] = 1;
// G->arc[2][5] = 1;
// G->arc[2][6] = 1;
// G->arc[2][9] = 1;
// G->arc[3][2] = 1;
// G->arc[3][13] = 1;
// G->arc[4][7] = 1;
// G->arc[5][8] = 1;
// G->arc[5][12] = 1;
// G->arc[6][5] = 1;
// G->arc[8][7] = 1;
// G->arc[9][10] = 1;
// G->arc[9][11] = 1;
// G->arc[10][13] = 1;
// G->arc[12][9] = 1;
完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 14
typedef int Status; /*Status是函数返回值类型*/
typedef char VertexType;
VertexType vexs1[MAXVEX];
/*邻接矩阵结构*/
typedef struct
{
VertexType vexs[MAXVEX]; /*vertex*/
int arc[MAXVEX][MAXVEX]; /*邻接矩阵*/
int numVertexes, numEdges; /*顶点个数,边个数*/
} MGraph;
//邻接表结构
typedef struct EdgeNode /*边表节点*/
{
int adjvex; /*邻接点域,存储该顶点对应的下标*/
int weight; //用于存储权值,非网图可不需要
struct EdgeNode *next; //链域,指向下一个邻接点
} EdgeNode;
typedef struct VertexNode //定点表结点
{
int in; //顶点入度
char data; //顶点域,存储顶点信息
EdgeNode *firstedge; //边表头指针
} VertexNode, AdjList[MAXVEX];
typedef struct
{
AdjList adjList;
int numVertexes, numEdges; //图中当前顶点数和边数
} graphAdjList, *GraphAdjList;
// function declaration
void CreateMGraph_matrix(MGraph *G);
void CreateMGraph_list(MGraph *G);
void CreateALGraph(MGraph G, GraphAdjList *GL);
Status TopologicalSort(GraphAdjList GL);
void menu();
void menu()
{
printf("Please input the method you want to bulid a graph:\n");
printf(" 1. Adjacent matrix 2. Adjacent list\n");
int choice;
scanf("%d", &choice);
}
void CreateMGraph_matrix(MGraph *G) //邻接矩阵法构建矩阵
{
int i, j, k, value;
G->numEdges = MAXEDGE;
G->numVertexes = MAXVEX;
G->arc[MAXVEX][MAXVEX] = {
0};
G->vexs[MAXVEX] = {
'0'};
printf("Please input number of vertexs and edges:\n");
scanf("%d %d", &G->numVertexes, &G->numEdges);
getchar();
printf("please input your vertexs\n");
for (i = 0; i < G->numVertexes; i++)
{
scanf("%c", &G->vexs[i]);
vexs1[i] = G->vexs[i];
}
//初始化
for (i = 0; i < G->numVertexes; i++)
for (j = 0; j < G->numVertexes; j++)
G->arc[i][j] = 0;
for (k = 0; k < G->numEdges; k++)
{
printf("please input the value of(vi,vj):\n");
scanf("%d %d %d", &i, &j, &value);
G->arc[i][j] = value;
}
//打印邻接矩阵
printf("The adjancent matirx is :\n");
for (i = 0; i < G->numVertexes; i++)
{
for (j = 0; j < G->numVertexes; j++)
printf("%d ", G->arc[i][j]);
printf("\n");
}
// G->arc[0][4] = 1;
// G->arc[0][5] = 1;
// G->arc[0][11] = 1;
// G->arc[1][2] = 1;
// G->arc[1][4] = 1;
// G->arc[1][8] = 1;
// G->arc[2][5] = 1;
// G->arc[2][6] = 1;
// G->arc[2][9] = 1;
// G->arc[3][2] = 1;
// G->arc[3][13] = 1;
// G->arc[4][7] = 1;
// G->arc[5][8] = 1;
// G->arc[5][12] = 1;
// G->arc[6][5] = 1;
// G->arc[8][7] = 1;
// G->arc[9][10] = 1;
// G->arc[9][11] = 1;
// G->arc[10][13] = 1;
// G->arc[12][9] = 1;
}
/*邻接矩阵构建邻接表*/
void CreateALGraph(MGraph G, GraphAdjList *GL)
{
int i, j;
EdgeNode *e;
*GL = (GraphAdjList)malloc(sizeof(graphAdjList));
(*GL)->numVertexes = G.numVertexes;
(*GL)->numEdges = G.numEdges;
for (i = 0; i < G.numVertexes; i++) //读入顶点信息,建立顶点表
{
(*GL)->adjList[i].in = 0;
(*GL)->adjList[i].data = G.vexs[i];
(*GL)->adjList[i].firstedge = NULL; //将边表置为空表
}
for (i = 0; i < G.numVertexes; i++) //建立边表
{
for (j = 0; j < G.numVertexes; j++)
{
if (G.arc[i][j] == 1)
{
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = j; //邻接序号为j
e->next = (*GL)->adjList[i].firstedge; //将当前顶点上的指向的节点指针赋值给e
(*GL)->adjList[i].firstedge = e; //将当前顶点的指针指向e
(*GL)->adjList[j].in++;
}
}
}
}
int find_index(char s)
{
for (int i = 0; i < MAXVEX; i++)
{
if (vexs1[i] == s)
return i;
}
return 0;
}
//拓扑排序,有环返回0,无环返回1并输出序列
Status TopologicalSort(GraphAdjList GL)
{
EdgeNode *e;
int i, k;
char gettop;
int top = 0; //用于栈指针下标
int count = 0; //用于统计输出顶点的个数
char *stack; //建立栈将入度为0的顶点入栈
stack = (char *)malloc(GL->numVertexes * sizeof(char));
for (i = 0; i < GL->numVertexes; i++)
if (0 == GL->adjList[i].in)
stack[++top] = vexs1[i]; //入度为0 的顶点入栈
int index;
while (top != 0)
{
gettop = stack[top--];
for (int kk = 0; kk < MAXVEX; kk++)
if (vexs1[kk] == gettop)
index = kk;
printf("%c -> ", GL->adjList[index].data);
count++; //输出i顶点,并计数
for (e = GL->adjList[find_index(gettop)].firstedge; e; e = e->next)
{
k = e->adjvex;
if (!(--GL->adjList[k].in)) /*将i顶点的邻接点的入度减一,如果减一后等于0,则入栈*/
stack[++top] = vexs1[k];
}
}
printf("\n");
if (count < GL->numVertexes)
return ERROR;
else
return OK;
}
int main(void)
{
MGraph G;
GraphAdjList GL;
int result;
CreateMGraph_matrix(&G);
CreateALGraph(G, &GL);
result = TopologicalSort(GL);
printf("result:%d", result);
return 0;
}
运行结果: