图的入门(一)

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

类型:有向图,无向图

 

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

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

 

posted @ 2019-09-14 08:42  白清欢  阅读(182)  评论(0编辑  收藏  举报