赞
踩
有向无环图:若一个有向图中不存在环,则称为有向无环图,简称DAG图。
有向无环图是描述含有公共子式的表达式的有效工具。例如表达式((a+b)*(b*(c+d))+(c+d)*e)*((c+d)*e)
可以用之前描述的二叉树来表示,仔细观察该表达式,可发现有一些相同的子表达式(c +d )和(c +d)*e,而在二叉树中,它们也重复出现。若利用有向无环图,则可实现对相同子式的共享,从而节省存储空间,下图为该表达式的有向无环图表示。
AOV网:若用DAG图表示一个工程,其顶点表示活动,用有向边<Vi , Vj >表示活动Vi 必须先于活动Vj 进行的这样一种关系,则将这种有向图称为顶点表示活动的网络,记为AOV网。在AOV网中,活动Vi 是活动 Vj的直接前驱,活动 Vj是活动Vi 的直接后继,这种前驱和后继关系具有传递性,且任何活动Vi 不能以它自己作为自己的前驱或后继。
拓扑排序:在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:
或定义为:拓扑排序是对有向无环图的顶点的一种排序, 它使得若存在一条从顶点 A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。
对一个AOV网进行拓扑排序的算法有很多,下面介绍比较常用的一种方法的步骤:
由于输出每个顶点的同时还要删除以它为起点的边,故采用邻接表存储时拓扑排序的时间复杂度为0(|V|+ |E|),采用邻接矩阵存储时拓扑排序的时间复杂度为0(|V|2 )。
在AOE网中仅有一个入度为0的顶点,称为开始顶点(源点),它表示整个工程的开始;网中也仅存在一个出度为0的顶点,称为结束顶点(汇点),它表示整个工程的结束。
在AOE网中,有些活动是可以并行进行的。从源点到汇点的有向路径可能有多条,并且这些路径长度可能不同。完成不同路径上的活动所需的时间虽然不同,但是只有所有路径上的活动都已完成,整个工程才能算结束。因此,从源点到汇点的所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动。
求关键路径的算法步骤如下:
对于关键路径,需要注意以下几点:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_VERTEX_NUM 20 // 最大顶点数 typedef struct { char vertex[MAX_VERTEX_NUM]; // 存放顶点信息 int edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 存放边信息 int vertex_num; // 顶点数 int edge_num; // 边数 } Graph; int indegree[MAX_VERTEX_NUM]; //存放每个顶点的入度 /*这里我们不要判断某个顶点的出度,在拓扑排序中我们用不到这些*/ //初始化顶点的入度数组 void Initindegree(Graph G){ //首先初始化入度数组 for(int i=0;i<G.vertex_num;i++){ indegree[i]=0; } //统计每个元素对应邻接矩阵列中1的个数即可判断有几条边进入 for(int i=0;i<G.vertex_num;i++){ int count=0; for(int j=0;j<G.vertex_num;j++){ if(G.edge[j][i]==1) count++; } indegree[i]=count; } } // 拓扑排序函数 bool Topologicalsort(Graph G) { char queue[MAX_VERTEX_NUM]; int front = -1, rear = -1; // 初始化队列,front和rear都设为0 // 首先把入度为0的顶点都进队列 for (int i = 0; i < G.vertex_num; i++) { if (indegree[i] == 0) { queue[++rear] = i; // 注意这里应该存储顶点的索引,而不是顶点的值 } } int count = 0; // 这个变量用来记录当前已输出的顶点数 while (front != rear) { int cur_vertex = queue[++front]; // 出队一个顶点,front原先是零,现在是1 printf("%c ", G.vertex[cur_vertex]); // 输出顶点的值 count++; // 已输出的顶点数加1 // 遍历以当前顶点为起点的所有边 for (int i = 0; i < G.vertex_num; i++) { if (G.edge[cur_vertex][i] == 1) { indegree[i]--; // 将这些边的终点的入度减1 if (indegree[i] == 0) { // 如果某个终点的入度变为0,就将其入队 queue[++rear] = i; } } } } if (count == G.vertex_num) { // 如果已输出的顶点数等于总顶点数,说明拓扑排序成功 return true; } else { // 否则说明存在环,拓扑排序失败 return false; } } int main(){ Graph G; G.vertex_num=5; G.edge_num=6; //人为构造图的顶点 for(int i=0;i<G.vertex_num;i++){ G.vertex[i]= 'A'+i; } for(int i=0; i<G.vertex_num; i++){ for(int j=0; j<G.vertex_num; j++){ G.edge[i][j]=0; } } //人为构造图的边 G.edge[0][1]=1; G.edge[0][3]=1; G.edge[1][3]=1; G.edge[1][2]=1; G.edge[3][4]=1; G.edge[2][4]=1; G.edge[3][2]=1; Initindegree(G); Topologicalsort(G); }
与我们自己手动排序的结果一样。
这个专栏接下来就是排序算法啦,让我们共同期待。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。