Kruskal Plim Dijkstra

63 阅读1分钟

1.Kruskal

public static HashSet<Edge> KruskalSTL(Graph graph){
    UnionFind unionFind = new UnionFind();
    unionFind.makeSets(graph.nodes.values());
    HashSet<Edge> set = new HashSet<>();  //需要返回的边集合
    if(graph==null) return set;
    PriorityQueue<Edge> queue = new PriorityQueue<>(new Comparator<Edge>() {
        @Override
        public int compare(Edge o1, Edge o2) {
            return o1.weight-o2.weight;
        }
    });
    for (Edge edge : graph.edges) { //  将所有的边放入队列
        queue.add(edge);
    }
    while (!queue.isEmpty()){
        Edge curEdge = queue.poll();
        //检查当前边curEdge的from和to节点是否属于一个集合
        if(!unionFind.isSameSet(curEdge.from,curEdge.to)){
            //不在同一集合下
            set.add(curEdge);
            unionFind.union(curEdge.from,curEdge.to);
        }
    }
    return set;
}

2.Plim

public static Set<Edge> PrimSTL(Graph graph) {
    HashSet<Edge> res = new HashSet<>();
    if (graph == null) return res;
    //set用于记录已经连通的节点
    HashSet<Node> set = new HashSet<>();
    //queue用于记录当前节点的边
    PriorityQueue<Edge> queue = new PriorityQueue<>();

    //for循环是针对森林,如果有未连通的分量可以,通过for循环可以找到,分量内部生成最小生成树
    for (Node node : graph.nodes.values()) {
        //随机选择一个节点
        if (!set.contains(node)) {
            set.add(node);
            //将该节点的所有边放入队列
            for (Edge edge : node.edges) {
                queue.add(edge);
            }


            while (!queue.isEmpty()) {
                //每次弹出权值最小的边,获取他指向的节点
                Edge curEdge = queue.poll();
                Node toNode = curEdge.to;
                //如果指向的节点不在集合里,将指向该节点边添加到最小生成树里,将指向的节点放入集合,并将指向节点所有边放入队列
                if(!set.contains(toNode)) {
                    set.add(toNode);
                    res.add(curEdge);
                    for (Edge edge : toNode.edges) {
                        queue.add(edge);
                    }
                }
            }
        }
    }

    return res;
}

3.Dijkstra

public static Map<Node,Integer> Dijkstra(Node node) {
    HashMap<Node, Integer> distanceMap = new HashMap<>();   //map key:表示图中的一个节点
                                                    //value:表示从node到key的最短路径
    if(node==null) return distanceMap;

    HashSet<Node> selectedNodes = new HashSet<>();            //  set用于存放已经更新完成的节点,以后不再更新
    distanceMap.put(node,0);                                  //  将源头节点放入map中

    Node minNode = getMinAndUnelectedNode(distanceMap,selectedNodes);     //选出未更新完成的节点中最小的一个
    while (minNode!=null) {
        int distance = distanceMap.get(minNode);
        for (Edge edge : minNode.edges) {
            if(!distanceMap.containsKey(edge.to)) {         //通过边第一次发现某节点,将该节点放入map中
                distanceMap.put(edge.to,edge.weight);
            }else {
                //minNode的值加上当前边的权值如果比edge.to自身值小,更新map中edge.to的值
                distanceMap.put(edge.to,Math.min(distanceMap.get(edge.to),distanceMap.get(minNode)+edge.weight));
            }
            //当前节点已经处理完毕,加入到selectedNodes中
            selectedNodes.add(minNode);
            //将minNode更新为未选择过的节点中最小的那个
            minNode = getMinAndUnelectedNode(distanceMap,selectedNodes);
        }
    }
    return distanceMap;
}

public static Node getMinAndUnelectedNode(HashMap<Node,Integer> distanceMap,HashSet<Node> selectedNodes) {
    int min = Integer.MAX_VALUE;
    Node minNode = null;
    for (Map.Entry<Node, Integer> entry : distanceMap.entrySet()) {
        if(!selectedNodes.contains(entry.getKey())) {
            min = Math.min(min, entry.getValue());
            minNode = min == entry.getValue()?entry.getKey():minNode;
        }
    }
    return minNode;
}