AOV网
一项工程经常被分为多个小的子工程,子工程之间存在一定的先后顺序,即某些子过程必须在其他的一些子过程完成之后才能开始.
在现代的管理中,人们常用有向图来描述和分析一项工程的计划和实施过程,子过程被称为活动(Activity),以顶点表示活动有向边表示活动之间的先后关系,这样的图称为AOV网.
标准的AOV网必须是一个有向无环图,如图:
拓扑排序
前驱活动:有向边起点的活动称为终点的前驱活动,只有当一个活动的前驱全部完成后,这个活动才能进行. 后驱活动:有向边终点的活动称为起点的后继活动.
什么是拓扑排序? 将AOV网中所有活动排成一个序列,使得每个活动的前驱活动都排在该活动的前面. 如上图的拓扑排序的结果是:
A,B,C,D,E,F或者A,B,D,C,E,F
实现思路
可以使用卡恩算法完成拓扑排序.
- 把所有入度为0的顶点放入存放结果的列表中,然后把这些顶点从图中去掉(具体实现中,删除顶点会破坏了原有的数据,所以一般不会删除)
- 重复操作1,知道找不到入度为0的顶点为止
如果列表中的元素个数和顶点个数相同,说明拓扑排序完成.
如果列表中元素个数少于顶点总数,说明图中有环,无法进行拓扑排序.
代码(基于图java实现)
public List<V> topologicalSort() {
//返回结果的list
List<V> list = new ArrayList<>();
//存放度为0的队列
Queue<Vertex<V, E>> queue = new LinkedList<>();
//维护顶点入度的hash表
Map<Vertex<V, E>, Integer> ins = new HashMap();
//初始化,将入度为0的节点加入queue,不为0的维护在ins里
vertices.forEach((V v, Vertex<V, E> vertex) -> {
//节点入度的数量
int inSize = vertex.inEdges.size();
if (inSize == 0) {
queue.offer(vertex);
} else {
ins.put(vertex, inSize);
}
});
while (!queue.isEmpty()) {
Vertex<V, E> vertex = queue.poll();
list.add(vertex.value);
//遍历顶点的出度边的顶点,对应的入度减1
for (Edge<V, E> edge : vertex.outEdges) {
int size = ins.get(edge.to) - 1;
if (size == 0) {
queue.offer(edge.to);
} else {
ins.put(edge.to, size);
}
}
}
return list;
}