zoukankan      html  css  js  c++  java
  • 图的入门(一)

    图的表示方法: 邻接表,邻接矩阵

    类型:有向图,无向图

    节点信息:入度,出度,节点值,连接的节点,连接的边

    package day7;
    
    import java.util.ArrayList;
    
    public class Node {
        public int value;
        public int in;
        public int out;
        public ArrayList<Node> next; //这里是list
        public ArrayList<Edge> edge;
        public Node(int value) {
            this.value = value;
            this.in = 0;
            this.out = 0;
            this.next = new ArrayList<>();
            this.edge = new ArrayList<>();
            
        }
    }
    View Code

    边信息:边权重,from的节点,to的节点

    package day7;
    
    public class Edge {
         public int value;
         public Node from;
         public Node to;
         public Edge(int value,Node from ,Node to) {
            this.value = value;
            this.from = from;
            this.to = to;
        }
    
    }
    View Code

    图:节点的集合+边的集合

    初始化:

    package day7;
    
    import java.util.HashMap;
    import java.util.HashSet;
    
    public class Graph {
        public HashMap<Integer, Node> nodes ;
        public HashSet<Edge> edges;
        
        public Graph() {
            this.nodes = new HashMap<Integer, Node>();
            this.edges = new HashSet<Edge>();
        }
        
        
        public  void creatGraph(int arr[][]) {
            for (int i = 0;i <arr.length ; i++) {//arr[i] ={from,to,value}
                Node from,to;
                if(!this.nodes.containsKey(arr[i][0])) {
                    from = new Node(arr[i][0]);
                }else {
                    from = this.nodes.get(arr[i][0]);
                }
                from.out++;
                
                if(!this.nodes.containsKey(arr[i][1])) {
                    to = new Node(arr[i][1]);
                }else {
                    to = this.nodes.get(arr[i][1]);
                };
                to.in ++;
                
                from.next.add(to);
                Edge edge = new Edge(arr[i][2], from, to);
                from.edge.add(edge);
                to.edge.add(edge);
                
                
                this.nodes.put(arr[i][0], from);
                this.nodes.put(arr[i][1], to);
                this.edges.add(edge);
                
            }
            
        }
        
    }
    View Code

    图的宽度优先遍历BDF

    1. 队列实现
    2. 从一个节点开始,依次按照宽进队列,然后弹出
    3. 弹出后,查找没有进过队列的临界点入队列
    4. 至队列为空
    package day7;
    
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.Queue;
    
    public class Code01_BFS {
        public static void bfs(Node node) {
            if(node == null) return ;
            //这里要用LinkList 而不是 PriorityQueue
            Queue <Node> que = new LinkedList<Node>();
            HashSet<Node> set = new HashSet<Node>();
            que.add(node);
            set.add(node);
            while(!que.isEmpty()) {
                Node cur = que.poll();
                System.out.print(cur.value+" ");
            
                for (Node next : cur.next) {
                    if(!set.contains(next)) {
                        que.add(next);
                        set.add(next);
                    }
                    
                }
                
            }
            
        }
        
        
        public static void main(String[] args) {
    //        int arr[][] = {
    //                {1,2,7,},
    //                {1,3,5,},
    //                {2,3,2,},};
            int arr [][]= {{1,2,1},{1,3,2},{2,4,3},{2,5,2},{4,6,4},};
            Graph graph = new Graph();
            graph.creatGraph(arr);
            bfs(graph.nodes.get(1));
            
        }
    }
    
    /*
     * 
     * 
     * */
    View Code


    图的深度优先遍历BDF

    1. 栈实现
    2. 从一个节点开始,依次按照深度入栈,然后弹出
    3. 当前节点弹出后,对比将该节点 下一个没有进过栈的邻接点,入栈。(当前节点也要入栈)
    4. 至栈空
    package day7;
    
    import java.util.HashSet;
    import java.util.Stack;
    
    public class Code02_DFS {
        public static void dfs (Node node) {
            //每次都忘了
            if (node == null) return ;
            HashSet<Node> set = new HashSet<Node>();
            Stack <Node> stack = new Stack<>();
            stack.add(node);
            set.add(node);
            
            while(!stack.isEmpty()) {
                Node cur =  stack.pop();
                System.out.print(cur.value+ " ");
                for (Node next : cur.next) {
                    if (! set.contains(next)) {
                        stack.add(next);
                        set.add(next);
                        cur = next;
                    }
                    
                }
                
            }
            
        }
        
        
        
        
        
        public static void main(String[] args) {
            int arr [][]= {
                    {1,2,1},{1,3,2},{2,4,3},{2,5,2},{4,6,4},};
            
    //        int arr [][]= {
    //                {1,2,1},{1,3,2},{1,4,2},
    //                {2,3,1},{2,4,3},{3,4,4},};
            Graph graph = new Graph();
            graph.creatGraph(arr);
            dfs(graph.nodes.get(1));
            
        }
    }
    View Code

    拓扑排序:

    要求:存在入度为0的节点有向图,并且没有环。(3个条件)

    package day7;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Queue;
    
    public class Code03_TopologicalSort {
        public static List<Node> topologicalSort (Graph graph) {
            //这里应该用Map,用set改变了节点的入度信息了,天机set用 add 。map用 put
            //HashSet<Node> set = new HashSet<Node>();
            HashMap<Node, Integer> inMap = new HashMap<Node, Integer>();
            Queue<Node> queue = new LinkedList<Node>();
            for (Node node: graph.nodes.values()) {
                inMap.put(node,node.in);
                if (node.in == 0) {
                    queue.add(node);
                }
            }
            List <Node> result = new  ArrayList<Node>();
            while (!queue.isEmpty()) {
                Node cur = queue.poll();
                result.add(cur);
                System.out.print(cur.value+" ");
                for (Node next : cur.next) {
                    inMap.put(next,inMap.get(next) -1 );
                    if(inMap.get(next) == 0) {
                        queue.add(next);
                    }
                }
            }
        return result;
        }
        
        
        public static void main(String[] args) {
            int arr [][]= {{1,2,1},{1,3,2},{3,2,3},{2,4,3},{2,5,2},{3,5,8},{4,5,3},{4,6,4},};
            Graph graph = new Graph();
            graph.creatGraph(arr);
            topologicalSort(graph);
            
        }
    }
    View Code

    最小生成树:保证连通的情况下,边权值和 最小的 集合   ,!!!!!!!函数返回边的集合!!!!!!!

    Kruskal:

      选边,从小到大(优先级队列),不形成回路(并查集),直到所有点都包括 || 所有边都遍历结束

    package day7;
    
    import java.util.Collection;
    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.PriorityQueue;
    import java.util.Queue;
    import java.util.Set;
    import java.util.Stack;
    
    
    /*
     * 最小生成树,返回边的集合
     * kruskal :
     *         选边,从小到大(优先级队列),不形成回路(并查集),直到所有点都包括 || 所有边都遍历结束
     */
    public class Code05_Kruskal {
        //并查集
        //两个map,一个father,head。
        public static class UnionFind{
            HashMap<Node, Node> fatherMap ;
            HashMap <Node ,Integer> sizeMap;
            public UnionFind() {
                fatherMap = new HashMap<Node, Node>();
                sizeMap = new HashMap<Node, Integer>();    
            }
            public void inital (Collection<Node> nodes) {
                this.fatherMap.clear();
                this.sizeMap.clear();
                for (Node cur : nodes) {
                    this.fatherMap.put(cur, cur);
                    this.sizeMap.put(cur, 1);
                }
            }
            
            public boolean isSameSet(Node a, Node b) {
                return this.findFather1(a) == this.findFather1(b);
            }
            public void union(Node a, Node b) {
                Node fathera = findFather1(a);
                Node fatherb = findFather1(b);
                int sizea  = this.sizeMap.get(fathera);
                int sizeb = this.sizeMap.get(fatherb);
                if (sizea <sizeb) {
                    this.fatherMap.put(fathera, fatherb);
                    this.sizeMap.put(fatherb, sizea +sizeb);
                }else {
                    this.fatherMap.put(fatherb, fathera);
                    this.sizeMap.put(fathera,sizea +sizeb );
                }
                
            }
            
            
            //递归版本
            public Node findFather2(Node cur) {
                if (!this.fatherMap.containsKey(cur)) return null;
                //get之前一定要记得判断null
                Node father = fatherMap.get(cur);
                while (father != cur) {
                    father = findFather2(father);
                }
                this.fatherMap.put(cur, father);
                return father;
            }
            //非递归版本
            public Node findFather1(Node cur) {
                if (!this.fatherMap.containsKey(cur)) return null;
                //get之前一定要记得判断null
                Node father = fatherMap.get(cur);
                Stack<Node> stack = new Stack<Node>(); 
                while (cur != father) {
                    stack.add(cur);
                    cur  = father;
                    father = fatherMap.get(cur);
                }
                while (!stack.isEmpty()) {
                    this.fatherMap.put(stack.pop(), father);
                }
                return father;
            }
            
            
            
        }
        
        
        
        public static class MyComaprator implements Comparator<Edge>{
    
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.value -o2.value;
            }
            
        }
        
        
        public static  Set<Edge> kruskal (Graph graph) {
            Queue<Edge> queue = new PriorityQueue<Edge>(new MyComaprator()); 
            UnionFind union = new UnionFind();
            union.inital(graph.nodes.values());
            for (Edge edge : graph.edges) {
                queue.add(edge);
            }
            Set<Edge> result = new HashSet<Edge>();
            while(!queue.isEmpty()) {
                Edge edge  = queue.poll();
                if(!union.isSameSet(edge.from, edge.to)) {
                    result.add(edge);
                    System.out.print(edge.value + " ");
                    union.union(edge.from, edge.to);
                }
            }
            return result;
            
        }
    
    
    
    
    
        public static void main(String[] args) {
            int arr [][]= {
                    {1,2,6},{1,3,1},{1,4,5},{2,3,5},{3,4,5},
                    {2,5,3},{3,5,6},{3,6,4},{4,6,2},{5,6,6},
                //    {2,1,6},{3,1,1},{4,1,5},{3,2,5},{4,3,5},
                //    {5,2,3},{5,3,6},{6,3,4},{6,4,2},{6,5,6},
                    };
            // 无向图1 5 3 4 2 
            // 有向图 1 5 3 4 2 。默认无向图。因为是选边,不考虑方向
            
            
    //        int arr [][]= {
    //                {1,2,1},{1,3,2},{2,4,3},{2,5,2},{4,6,4},};
            Graph graph = new Graph();
            graph.creatGraph(arr);
            kruskal(graph);
            
        }
    
    
    
    }
    View Code

    Prim:

    1. 从节点出发,查找相邻的边,
    2. 选择最小的边,查找边连接的节点是否出现过,
    3. 未出现,将边加入结果集,解锁新的节点(解锁新的边),新加入的边同原来的边一起重复2.
    package day7;
    
    import java.util.Comparator;
    import java.util.HashSet;
    /*
     * 最小生成树:返回边的集合
     * Prim:从点出发,查找相邻边,选择最小的,查看边相邻的节点是否出现过
     *         未出现,加入result,解锁新变和原来的边一起,找最小的
     *         出现继续
     * 
     */
    import java.util.PriorityQueue;
    import java.util.Set;
    
    public class Code04_Prim {
        
        public static class MyComparator implements Comparator<Edge>{
            @Override
            public int compare(Edge arg0, Edge arg1) {
                return arg0.value - arg1.value;
            }
            
        }
        
        
        public static Set<Edge> prim (Graph graph){
            HashSet<Node> set = new HashSet<Node> ();
            PriorityQueue<Edge> queue = new PriorityQueue<Edge>(new MyComparator()); 
            Set<Edge> result = new HashSet<Edge>();
            //important
            for (Node node  : graph.nodes.values()) {
                
                if (!set.contains(node)) {
                    set.add(node);
                    for (Edge edge : node.edge) {
                        queue.add(edge);
                    }
                    while (!queue.isEmpty()) {
                        Edge edge = queue.poll();
                        Node toNode = edge.to;
                        if(!set.contains(toNode)) {
                            set.add(toNode); //添加新点,从新点出发。
                            result.add(edge);
                            System.out.println("from " +edge.from.value+" to "+edge.to.value+" vlaue "+ edge.value );
                            for (Edge nextedge : toNode.edge) {
                                queue.add(nextedge);
                            }
                        }                    
                    }                
                }
            }
            return result;
        }
        
        
        
        
        public static void main(String[] args) {
            int arr [][]= {
                    {1,2,6},{1,3,1},{1,4,5},{2,3,5},{3,4,5},
                    {2,5,3},{3,5,6},{3,6,4},{4,6,2},{5,6,6},
            //        {2,1,6},{3,1,1},{4,1,5},{3,2,5},{4,3,5},
            //        {5,2,3},{5,3,6},{6,3,4},{6,4,2},{6,5,6},
                    };        
            // 无向图1 5 3 4 2 
            // 有向图   1 4 5 6 3 
            
            
    //        int arr [][]= {
    //                {1,2,1},{1,3,2},{2,4,3},{2,5,2},{4,6,4},};
            Graph graph = new Graph();
            graph.creatGraph(arr);
            prim(graph);
    
        }
    
        
    }
    View Code

     

  • 相关阅读:
    tensorflow_知识点
    Win10 1803 谷歌内核浏览器出现假死现象的解决方法汇总
    今日笑话
    留存率例子(待优化)
    安装ODOO13
    freepascal获取进程列表
    vba给图片添加logo
    wps中开始支持javascript了
    获取本地ip
    判断素数
  • 原文地址:https://www.cnblogs.com/codinghard/p/11518269.html
Copyright © 2011-2022 走看看