概念:

1)在图中找到所有入度为0的点输出
2)把所有入度为0的点在图中删掉,继续找入度为0的点输出,周而复始
3)图的所有点都被删除后,依次输出的顺序就是拓扑排序

要求:有向图且其中没有环
应用:事件安排、编译顺序

1、算法实现思路

1.1、思路:


拓扑排序,其实就是寻找一个入度为0的顶点,该顶点是拓扑排序中的第一个顶点序列,将之标记删除,然后将与该顶点相邻接的顶点的入度减1,再继续寻找入度为0的顶点,直至所有的顶点都已经标记删除或者图中有环。

从上可以看出,关键是寻找入度为0的顶点。

一种方式是遍历整个图中的顶点,找出入度为0的顶点,然后标记删除该顶点,更新相关顶点的入度,由于图中有V个顶点,每次找出入度为0的顶点后会更新相关顶点的入度,因此下一次又要重新扫描图中所有的顶点。故时间复杂度为O(V^2)

由于删除入度为0的顶点时,只会更新与它邻接的顶点的入度,即只会影响与之邻接的顶点。但是上面的方式却遍历了图中所有的顶点的入度。

改进的另一种方式是:先将入度为0的顶点放在栈或者队列中。当队列不空时,删除一个顶点v,然后更新与顶点v邻接的顶点的入度。只要有一个顶点的入度降为0,则将之入队列。此时,拓扑排序就是顶点出队的顺序。该算法的时间复杂度为O(V+E)

java 拓扑图绘制 拓扑图规划_java 拓扑图绘制

 

java 拓扑图绘制 拓扑图规划_java 拓扑图绘制_02

java 拓扑图绘制 拓扑图规划_java 拓扑图绘制_03

java 拓扑图绘制 拓扑图规划_算法_04

java 拓扑图绘制 拓扑图规划_Graph_05

1.2、代码:

//图
public class Graph {
    //点集合,代表编号为N的节点是啥
    public HashMap<Integer, Node> nodes;
    //边集合
    public HashSet<Edge> edges;

    public Graph() {
        nodes = new HashMap<>();
        edges = new HashSet<>();
    }
}
// directed graph and no loop
public static List<Node> sortedTopology(Graph graph) {
    // key:某一个node
    // value:剩余的入度
    HashMap<Node, Integer> inMap = new HashMap<>();
    // 入度为0的点,才能进这个队列
    Queue<Node> zeroInQueue = new LinkedList<>();
    for (Node node : graph.nodes.values()) {
        //保存每个节点以及该节点的入度
        inMap.put(node, node.in);
        if (node.in == 0) {
            zeroInQueue.add(node);
        }
    }
    // 拓扑排序的结果,依次加入result
    List<Node> result = new ArrayList<>();
    while (!zeroInQueue.isEmpty()) {
        Node cur = zeroInQueue.poll();
        result.add(cur);
        for (Node next : cur.nexts) {
            //当前节点的邻居入度减去1
            inMap.put(next, inMap.get(next) - 1);
            if (inMap.get(next) == 0) {
                zeroInQueue.add(next);
            }
        }
    }
    return result;
}