拓扑排序

429 阅读2分钟

AOV网

一项工程经常被分为多个小的子工程,子工程之间存在一定的先后顺序,即某些子过程必须在其他的一些子过程完成之后才能开始. 在现代的管理中,人们常用有向图来描述和分析一项工程的计划和实施过程,子过程被称为活动(Activity),以顶点表示活动有向边表示活动之间的先后关系,这样的图称为AOV网. 标准的AOV网必须是一个有向无环图,如图: AOV网示例

拓扑排序

前驱活动:有向边起点的活动称为终点的前驱活动,只有当一个活动的前驱全部完成后,这个活动才能进行. 后驱活动:有向边终点的活动称为起点的后继活动.

什么是拓扑排序? 将AOV网中所有活动排成一个序列,使得每个活动的前驱活动都排在该活动的前面. 如上图的拓扑排序的结果是:A,B,C,D,E,F或者A,B,D,C,E,F

实现思路

可以使用卡恩算法完成拓扑排序.

  1. 把所有入度为0的顶点放入存放结果的列表中,然后把这些顶点从图中去掉(具体实现中,删除顶点会破坏了原有的数据,所以一般不会删除)
  2. 重复操作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;
	}