左程云 Java 笔记--图

本文详细介绍了图结构的构建,包括HashMap和HashSet的使用,并涵盖了宽度优先遍历(BFS)、广度优先遍历(BFS)的实现,拓扑排序方法,以及Kruskal和Prim算法在无向图中求最小生成树的应用。最后,还探讨了Dijkstra算法用于计算有权值边的最短路径。
摘要由CSDN通过智能技术生成


图结构

构建

public class Graph {
    public HashMap<Integer,Node> nodes;
    public HashSet<Edge> edges;

    public Graph() {
        nodes = new HashMap<Integer, Node>();
        edges = new HashSet<Edge>();
    }
}

public class Node {
    public int value;
    public int in;
    public int out;
    public ArrayList<Node> nexts;
    public ArrayList<Node> edges;

    public Node(int value) {
        this.value = value;
        in = 0;
        out = 0;
        nexts = new ArrayList<>();
        edges = new ArrayList<>();
    }
}

public class Edge {
    public int weight;
    public Node from;
    public Node to;

    public Edge(int weight, Node from, Node to) {
        this.weight = weight;
        this.from = from;
        this.to = to;
    }
}

转换

public static Graph creatGraph(Integer[][] matrix){
        Graph graph = new Graph();
        for (int i = 0; i < matrix.length; i++) {
            Integer from = matrix[i][0];
            Integer to = matrix[i][1];
            Integer weitht = matrix[i][2];
            if (!graph.nodes.containsKey(from)){
                graph.nodes.put(from,new Node(from));
            }
            if (!graph.nodes.containsKey(to)){
                graph.nodes.put(to,new Node(to));
            }
            Node fromNode = graph.nodes.get(from);
            Node toNode = graph.nodes.get(to);
            Edge newEdge = new Edge(weitht,fromNode,toNode);
            fromNode.nexts.add(toNode);
            fromNode.out++;
            toNode.in++;
            fromNode.edges.add(newEdge);
            graph.edges.add(newEdge);
        }
        return graph;
    }    

遍历

图的宽度优先遍历

1,利用队列实现
2,从源节点开始依次按照宽度进队列,然后弹出
3,每弹出一个点,把该节点所有没有进过队列的邻接点放入队列
4,直到队列变空

    //宽度优先遍历
    public static void bfs(Node node){
        if (node == null) return;
        Queue<Node> queue = new LinkedList<>();
        HashSet<Node> set = new HashSet<>();
        queue.add(node);
        set.add(node);
        while (!queue.isEmpty()){
            Node cur = queue.poll();
            System.out.println(cur.value);
            for (Node next : cur.nexts) {
                if (!set.contains(next)){
                    set.add(next);
                    queue.add(node);
                }
            }
        }
    }

广度优先遍历

1,利用栈实现
2,从源节点开始把节点按照深度放入栈,然后弹出
3,每弹出一个点,把该节点下一个没有进过栈的邻接点放入栈
4,直到栈变空
在这里插入图片描述

    //深度优先遍历
    public static void dfs(Node node){
        if (node == null) return;
        Stack<Node> stack = new Stack<>();
        HashSet<Node> set = new HashSet<>();
        stack.add(node);
        set.add(node);
        System.out.println(node.value);
        while (!stack.isEmpty()){
            Node cur = stack.pop();
            for (Node next : cur.nexts) {
                if (!set.contains(next)){
                    stack.push(cur);
                    stack.push(next);
                    set.add(node);
                    System.out.println(next.value);
                    break;
                }
            }
        }
    }

拓扑排序

入度为0的点

    //拓扑排序
    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);
            }
        }
        //开始拓扑排序
        List<Node> res = new ArrayList<>();
        while (!zeroInQueue.isEmpty()){
            Node cur = zeroInQueue.poll();
            res.add(cur);
            for (Node next : cur.nexts) {
                inMap.put(next,inMap.get(next)-1);//入度-1
                if (inMap.get(next) == 0){
                    zeroInQueue.add(next);
                }
            }
        }
        return res;
    }

最小生成树

在这里插入图片描述

kruskal算法(无向图)

适用范围:要求无向图
从最小的边开始,如果加上没有形成环就加上,如果形成环就不加

    public static class MySet{
        public HashMap<Node,List<Node>> setMap;

        public MySet(List<Node> nodes){
            for (Node node : nodes) {
                List<Node> set = new ArrayList<>();
                set.add(node);
                setMap.put(node,set);
            }
        }

        public boolean isSameSet(Node from,Node to){
            List<Node> fromSet = setMap.get(from);
            List<Node> toSet = setMap.get(to);
            return fromSet == toSet;
        }

        public void union(Node from, Node to){
            List<Node> fromSet = setMap.get(from);
            List<Node> toSet = setMap.get(to);

            for (Node tonode : toSet) {
                fromSet.add(tonode);
                setMap.put(tonode,fromSet);
            }
        }
    }

prim算法(无向图)

适用范围:要求无向图

    //prim算法(无向图)
    public static Set<Edge> primMst(Graph graph){
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());

        HashSet<Node> set = new HashSet<>();

        Set<Edge> res = new HashSet<>();

        for (Node node : graph.nodes.values()) {
            if (!set.contains(node)){
                set.add(node);
                for (Edge edge : node.edges) {//由一个点,解锁它相邻的边
                    priorityQueue.add(edge);
                }
                while (!priorityQueue.isEmpty()){
                    Edge edge = priorityQueue.poll();//弹出最小的边
                    Node tonode = edge.to;//可能是一个新的点
                    if (!set.contains(tonode)){ //如果是新的点 重复的点就跳过了
                        set.add(tonode);
                        res.add(edge);
                        for (Edge nextedge : tonode.edges) {
                            priorityQueue.add(nextedge);
                        }
                    }
                }
            }
        }
        return  res;
    }
=================
   private static class EdgeComparator implements Comparator<Edge> {
        @Override
        public int compare(Edge o1, Edge o2) {
            return o1.weight - o2.weight;
        }
    }

Dijkstra算法

适用范围:可以有权值为负数的边 但是不能有累加和为负数的环
单元最短路径
在这里插入图片描述
在这里插入图片描述

    //Dijkstra算法
    public static HashMap<Node,Integer> dijkstra(Node head){
        //从head出发到所有点的最小距离
        // Key:从head出发到key
        //value:从head出发到key的最小值
        //如果在表中,没有T的记录,含义是从head出发到T这个点的距离为正无穷
        HashMap<Node,Integer> distanceMap = new HashMap<>();
        distanceMap.put(head,0);
        //已经求过的点,存在selectedNodes中
        HashSet<Node> selectedNode = new HashSet<>();
        Node minNode = getMinDistanceAndUnseLectedNode(distanceMap,selectedNode);
        while (minNode != null){
            int distance = distanceMap.get(minNode);
            for (Edge edge : minNode.edges) {
                Node toNode = edge.to;
                if (!distanceMap.containsKey(toNode)){
                    distanceMap.put(toNode,distance+edge.weight);
                }
                distanceMap.put(edge.to,Math.min(distanceMap.get(toNode),
                        distance+ edge.weight));
            }
            selectedNode.add(minNode);
            minNode = getMinDistanceAndUnseLectedNode(distanceMap,selectedNode);
        }
        return distanceMap;
    }

    private static Node getMinDistanceAndUnseLectedNode(HashMap<Node, Integer> distanceMap, HashSet<Node> touchedNode) {
        Node minNode = null;
        int minDistance  = Integer.MIN_VALUE;
        for (Map.Entry<Node, Integer> entry : distanceMap.entrySet()) {
            Node node = entry.getKey();
            int distancd = entry.getValue();
            if(!touchedNode.contains(node) && distancd < minDistance){
                minNode = node;
                minDistance = distancd;
            }
        }
        return minNode;
    }

总结

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值