左程云算法day7 图

本文介绍了图的两种存储方式——邻接表和邻接矩阵,并提供了创建图的代码示例。接着,详细阐述了宽度优先遍历(BFS)和深度优先遍历(DFS)的实现,以及拓扑排序的算法。此外,还讨论了 Kruskal 算法和 Prim 算法在求解最小生成树问题中的应用。
摘要由CSDN通过智能技术生成

图的存储方式:邻接表、邻接矩阵

图的题目采用不同的存储方式,coding不同,但是算法是一致的。

//图的结构1
public class graph {
    public class Node {
        int value;
        Node left;
        Node right;
    }
    public HashMap<Integer,Node> nodes;
    public HashSet<Edge> edges;

    public Graph(){
        nodes = new HashMap<>();
        edges = new HashSet<>();
    }
}

建立图

public class CreateGraph {
    public static Graph createGraph(Integer[][] matrix){
        Graph graph = new Graph();
        for (int i = 0; i < matrix.length; i++) {
            int from = matrix[i][0];
            int to = matrix[i][1];
            int weight = matrix[i][2];
            if (!graph.nodes.containsKey(from)){
                graph.nodes.put(from,new Node(from));//加入编号为from的新节
            }
            if(!graph.nodes.containsKey(to)){
                graph.nodes.put(to,new Node(to));
            }
            /*经过上述阶段就确定了有from 和to 的节点*/
            Node fromNode =graph.nodes.get(from);
            Node toNode = graph.nodes.get(to);

            /*得到了from和to的节点后,就可以往cur的节点填充信息*/
            Edge newEdge  = new Edge(weight,fromNode,toNode);
            fromNode.nexts.add(toNode);
            fromNode.out++;
            toNode.in++;
            fromNode.edges.add(newEdge);//给from添加一条出度
            graph.edges.add((newEdge));

        }
        return graph;
    }
}

图的宽度优先遍历:

利用队列实现;

从源节点开始依次按照宽度进入队列,然后弹出

每弹出一个点,把该节点所有没有进过对垒的邻接点放入队列

直到队列变空

public class GraphBFS {
    public static void graphBFS(Node head){
        Queue<Node> queue = new LinkedList<Node>();
        HashSet<Node> set = new HashSet<>();
        queue.add(head);
        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(next);
                }

            }
        }
    }
}

广度优先遍历:

利用栈实现

从源节点开始把点按照节深度入栈,然后弹出

 每弹出一个点,把该节点下一个没有进过栈的邻接点放入到栈内

直到栈变空

public class GraphDFS {
    public static void graphdfs(Node head){
        Stack<Node> stack = new Stack<Node>();
        HashSet<Node> set = new HashSet<Node>();
        stack.push(head);
        set.add(head);
        while(!stack.isEmpty()){
            Node cur = stack.pop();
            System.out.println(head.value);
            for(Node next: cur.nexts){
                if(!set.contains(next)){
                    stack.push(cur);
                    stack.push(next);
                    set.add(next);
                    System.out.println(next.value);
                    break;//跳出这个for循环
                }
                
            }
        }
    }
}

拓扑排序:可以有效解决编译依赖这类型的问题

拓扑排序必须遵守的要求:不能有环

public class SortedTopology {
    public static List<Node> sortedtopology(Graph graph){
        HashMap<Node,Integer> inMap = new HashMap<>();//用来春芳每个的入度
        Queue<Node> zeroInQueue = new LinkedList<>();//用来存放所有入度为零的节点
        for(Node node:graph.nodes.values()){
            inMap.put(node,node.in);//把所有的点情况都存放到inMap中
            if(node.in==0){
                zeroInQueue.add(node);
            }
        }
        /*以上为准备工作*/
        List<Node> result = new ArrayList<>();//作为输出结果
        while (!zeroInQueue.isEmpty()){
            Node cur = zeroInQueue.poll();
            result.add(cur);
            for (Node next:cur.nexts){
                inMap.put(next,inMap.get(next)-1);//入度减1
                if(inMap.get(next)==0){
                    zeroInQueue.add(next);
                }
            }
        }
        return result;
    }
}

kruskal算法:从最小的边开始,只要不形成环就可以加上

判断算法不形成环:用集合思想:相连的边形成一个集合,每次加入一条边后改变的出边若存在于其中改变的一个集合的话就可认为形成环。

public class Kruskal {
    public static class Mysets{
        public HashMap<Node, List<Node>> setMap = null;
        public Mysets(List<Node> nodes) {//初始化,把所有的点都辅导setMap里面

            for (Node cur : nodes) {
                List<Node> set=new ArrayList<Node>();
                set.add(cur);
                setMap.put(cur,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);
            }
        }
    }
    public static Set<Edge> kruskalMST(Graph graph){
        for (int i = 0; i < graph.nodes.size(); i++) {
            Mysets mysets = new Mysets(graph.nodes.values());
        }
    }
}

prim算法:适用范围:无向图

随意找一个点:将与其相连的边解锁,找出最短的边,将与to的节点相连的边解锁,周而复始,直到所有的点都存到集合中。

Dijkstra算法:每次加入一个点,重新找到一条最短路径,锁定该点然后将加入的点重新遍历一遍,找出加入点后可以锁定的最近目的点,周而复始。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值