17.4:图的拓扑排序

拓扑序一定是有向无环图。

拓扑排序不唯一

在这里插入图片描述
在这里插入图片描述

拓扑排序方法一:

利用入度为零进行排序

思路:谁的入度为0,谁就是开始节点,将开始节点打印完之后,将开始节点的直接邻居的入度减1,然后重复。

在这里插入图片描述

package algorithmbasic.class17;

import java.util.*;

//图的拓扑排序
public class TopologySort {
    
    
    public static List<Node> sortedTopology(Graph graph) {
    
    
        //result用来盛放排序结果。
        List<Node> result = new ArrayList<>();
        //inmap存放节点与入度的对应值。
        //key ——> 某个节点, value ——> 剩余入度
        HashMap<Node, Integer> inmap = new HashMap<>();
        //只有节点的入度为0才可以进入此队列。
        Queue<Node> inZeroQueue = new LinkedList<>();

        for (Node node : graph.nodes.values()) {
    
    
            inmap.put(node, node.in);
            if (node.in == 0) {
    
    
                inZeroQueue.add(node);
            }
        }

        Node cur = inZeroQueue.poll();
        result.add(cur);
        for (Node next : cur.nexts) {
    
    
            //剩余入度减1.
            inmap.put(next, inmap.get(next) - 1);
            if (inmap.get(next) == 0) {
    
    
                inZeroQueue.add(next);
            }
        }
        return result;
    }
}

拓扑排序方法二:

利用点次进行排序。

在这里插入图片描述

点次越大的,排序位置越靠前。

而且我发现可以使用递归进行求点次。我们要求0的点次,那就需要求他的直接邻居1,2,3的点次,然后对邻居的点次求和再加1,就是0的点次。我们可以将每个点的点次放在一个表里面,这个表记录着哪个节点的点次对应着多少。这样我们再求其他节点点次时直接从表里拿就行,减少重复性工作。

思路:
1:创建一个表 HashMap<DirectedGraphNode, Record> order = new HashMap<>() 用来记录每个节点对应的点次是多少。

2:遍历整个图中的每一个节点,记录其点次。

3:创建一个有序表ArrayList records = new ArrayList<>() 用来记录点次。

4:根据点次进行由大到小的排序。records.sort(new MyComparator());

5:然后再创建一个有序表ArrayList dnodes = new ArrayList<>() 根据点次的顺序记录节点。

注意为什么要创建Record这个内部类。因为在 “ 根据点次的顺序记录节点” 时,我们需要根据点次找到对应的节点,使用map是不可以的,因为点次大小有重复的。所以我们采用内部类的方法,这样每个点次都会有一一对应的节点。

package algorithmbasic.class17;
//图的拓扑排序方法二

import java.util.*;

// OJ链接:https://www.lintcode.com/problem/topological-sorting
public class TopologicalOrderDFS2 {
    
    
    /**
     * 节点内部类
     */
    // 不要提交这个类
    public static class DirectedGraphNode {
    
    
        public int label;
        public ArrayList<DirectedGraphNode> neighbors;

        public DirectedGraphNode(int x) {
    
    
            label = x;
            neighbors = new ArrayList<DirectedGraphNode>();
        }
    }
    
    /**
     * 点次内部类。
     */

    //记录某个节点的点次。
    public static class Record {
    
    
        public DirectedGraphNode node;
        //点次。
        public long nodes;

        public Record(DirectedGraphNode node, long nodes) {
    
    
            this.node = node;
            this.nodes = nodes;
        }
    }

    /**
     * topSort方法
     * 传入一张图的所有节点,返回排序好后的所有节点。
     */

    public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
    
    
        //采用计算每个节点点次的方法。
        //建立一张表用来记录每个节点对应的点次是多少。
        HashMap<DirectedGraphNode, Record> order = new HashMap<>();
        ArrayList<Record> records = new ArrayList<>();
        ArrayList<DirectedGraphNode> dnodes = new ArrayList<>();

        //遍历图中每个节点,并记录每个节点出现的点次。
        for (DirectedGraphNode cur : graph) {
    
    
            Record record = process(cur, order);
            records.add(record);
            //order.put(cur, record);
        }
        //Arrays.sort(records,new MyComparator());
        records.sort(new MyComparator());
        for (Record r : records) {
    
    
            dnodes.add(r.node);//这就是为什么要建立Record这个内部类的原因。
        }
        return dnodes;
    }
    
    /**
     * 求点次的方法。
     */

    //传入一个节点返回这个节点的点次。在递归的过程当中每个节点的点次其实都已经记录好了。
    public static Record process(DirectedGraphNode node, HashMap<DirectedGraphNode, Record> order) {
    
    
        if (order.containsKey(node)) {
    
    
            return order.get(node);
        }
        //order中没有该点。
        long count = 0;
        for (DirectedGraphNode n : node.neighbors) {
    
    
            Record r = process(n, order);
            count += r.nodes;
        }
        Record record = new Record(node, count + 1);
        //先把当前节点及其点次放入map中然后再返回。这样我们再求其他节点点次时直接从表里拿就行,减少重复性工作。
        order.put(node, record);
        return record;
    }

    /**
     * 比较器
     */
    
    public static class MyComparator implements Comparator<Record> {
    
    
        @Override
        public int compare(Record o1, Record o2) {
    
    
            //不要将long类型数据强制转换成int类型,会出现溢出和截断的风险,导致数据出现错误。
            //例如2147483648L -> int:-2147483648
            //它超过了int类型的最大值 2147483647。当将其强制转换为int类型时,结果被截断为int类型的最小值 -2147483648。
            //return (int)(o2.nodes - o1.nodes);
            return o1.nodes == o2.nodes ? 0 : (o1.nodes > o2.nodes ? -1 : 1);
        }
    }
}

拓扑排序方法三:

根据深度进行排序

在这里插入图片描述

package algorithmbasic.class17;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;

public class TopologicalOrderDFS1 {
    
    

    /**
     * 节点内部类
     */

    public static class DirectedGraphNode {
    
    
        public int label;
        public ArrayList<DirectedGraphNode> neighbors;

        public DirectedGraphNode(int x) {
    
    
            label = x;
            neighbors = new ArrayList<DirectedGraphNode>();
        }
    }

    /**
     * 深度内部类。
     */

    public static class Deep {
    
    
        public long deep;
        public DirectedGraphNode node;

        public Deep(long deep, DirectedGraphNode node) {
    
    
            this.deep = deep;
            this.node = node;
        }
    }

    /**
     * topSort方法
     */

    public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
    
    
        HashMap<DirectedGraphNode, Deep> order = new HashMap<>();
        ArrayList<Deep> deeps = new ArrayList<>();
        ArrayList<DirectedGraphNode> dNodes = new ArrayList<>();

        for (DirectedGraphNode node : graph) {
    
    
            Deep d = process(node, order);
            deeps.add(d);
        }
        deeps.sort(new MyComparator());
        for (Deep d : deeps) {
    
    
            dNodes.add(d.node);
        }
        return dNodes;
    }


    public static Deep process(DirectedGraphNode node, HashMap<DirectedGraphNode, Deep> order) {
    
    
        if (order.containsKey(node)) {
    
    
            return order.get(node);
        }
        long max = Long.MIN_VALUE;
        for (DirectedGraphNode n : node.neighbors) {
    
    
            Deep d = process(n, order);
            max = Math.max(max, d.deep);
        }
        Deep deep = new Deep(max + 1, node);
        order.put(node, deep);
        return deep;
    }

    public static class MyComparator implements Comparator<Deep> {
    
    
        @Override
        public int compare(Deep o1, Deep o2) {
    
    
            return o1.deep == o2.deep ? 0 : (o1.deep > o2.deep ? -1 : 1);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/SCR1209/article/details/131024214