图(java实现)

一、图的表示方式

1、邻接矩阵

如果是带权图,将1换成权值。 

2、邻接表

表示与1 关联的有 1,2,3,4

 二、图的实现。

图:

    /**
     * 图。
     * notes:所有的节点。
     * edges:所有的边。
     */
    static class Graph {
        HashMap<Integer, Note> notes;
        HashSet<Edge> edges;

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

节点: 

    /**
     * 图的节点。
     * value:序号
     * in:入度
     * out:出度
     * nexts:后续节点们
     * edges:当前节点发出的边
     */
    static class Note {
        int value;
        int in;
        int out;
        ArrayList<Note> nexts;
        ArrayList<Edge> edges;

        public Note() {

        }

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

边:

    /**
     * 边。
     * weight:边的权重
     * from:起始节点
     * to:终点
     */
    static class Edge {
        int weight;
        Note from;
        Note to;

        public Edge() {

        }

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

图的初始化:

    /**
     * 图的初始化。
     *
     * @param arr {{weight, 起点序号, 终点序号}, {},{}}
     */
    public static void generatorGraph(int[][] arr) {
        Graph graph = new Graph();
        for (int i = 0; i < arr.length; i++) {
// 创建起点,终点,边。
            int weight = arr[i][0];
            int from = arr[i][1];
            int to = arr[i][2];
            if (!graph.notes.containsKey(from)) {
                graph.notes.put(from, new Note(from));
            }

            if (!graph.notes.containsKey(to)) {
                graph.notes.put(to, new Note(to));
            }
            Note noteF = graph.notes.get(from);
            Note noteT = graph.notes.get(to);

            Edge edge = new Edge(weight, noteF, noteT);
//初始化节点
            noteF.out++;
            noteT.in++;
            noteF.nexts.add(noteT);
            noteF.edges.add(edge);
//边加入图中
            graph.edges.add(edge);

        }
    }

三、图的常用算法。

1、遍历搜索算法

(1)、广度优先搜索(bfs)

将节点的每一个下一个节点加入队列中,用set避免重复。

//用set去重,加入过队列中的节点不再加入队列
    public static void bfs(Note root) {
        Note note = root;
        Queue<Note> queue = new LinkedList<>();
        HashSet<Note> set = new HashSet<>();
        queue.add(note);
        set.add(note);
        while (!queue.isEmpty()) {
            note = queue.poll();
            for (Note next : note.nexts) {
                if (!set.contains(next)) {
                    set.add(next);
                    queue.add(next);
                }
            }
            System.out.println(note.value);
        }
    }

(2)、深度优先搜索(dfs)

栈中弹出节点,当前节点有下节点不在set中,就输出下节点,并将当前节点下节点加入栈中。

    public static void dfs(Note note) {
        Stack<Note> stack = new Stack<>();
        HashSet<Note> set = new HashSet<>();
        stack.add(note);
        set.add(note);
        System.out.println(note);
        while (!stack.isEmpty()) {
            Note cur = stack.pop();
            for (Note next : cur.nexts) {
                if (!set.contains(next)) {
                    stack.add(cur);
                    stack.add(next);
                    set.add(next);
                    System.out.println(next);
                    break;
                }
            }
        }
    }

2、最小生成树算法

(1)、kruskal算法(无向图)

每次选择权重最小的能够连接新节点的边,直到所有节点连接在一起。

代码:用优先级队列将边以权重排列,每次弹出权重最小的边 并将边的端点用并查集连接起来。

    public static Set<Edge> kruskal(Graph graph) {
        UnionSet unionSet = new UnionSet(graph.notes.values());
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>((Edge e1, Edge e2) -> e1.weight - e2.weight);
        for (Edge edge : graph.edges) {
            priorityQueue.add(edge);
        }
        Set<Edge> resultSet = new HashSet<>();
        while (!priorityQueue.isEmpty()) {
            Edge edge = priorityQueue.poll();
            Note fromNote = edge.from;
            Note toNote = edge.to;
            if (!unionSet.isSameSet(fromNote, toNote)) {
                resultSet.add(edge);
                unionSet.union(fromNote, toNote);
            }
        }
        return resultSet;
    }

并查集:

    static class UnionSet {
        HashMap<Note, Note> fatherMap = new HashMap<>();
        HashMap<Note, Integer> sizeMap = new HashMap<>();

        public UnionSet(Collection<Note> notes) {
            for (Note note : notes) {
                fatherMap.put(note, note);
                sizeMap.put(note, 1);
            }
        }

        public Note getHead(Note note) {
            Note father = fatherMap.get(note);
            while (father != note) {
                father = getHead(father);
            }
            fatherMap.put(note, father);
            return father;
        }

        public boolean isSameSet(Note note1, Note note2) {
            Note head1 = getHead(note1);
            Note head2 = getHead(note2);
            return head1 == head2;
        }

        public void union(Note note1, Note note2) {
            Note head1 = getHead(note1);
            Note head2 = getHead(note2);
            int size1 = sizeMap.get(head1);
            int size2 = sizeMap.get(head2);

            if (size1 < size2) {
                fatherMap.put(head1, head2);
                sizeMap.put(head2, size1 + size2);
            } else {
                fatherMap.put(head2, head1);
                sizeMap.put(head1, size1 + size2);
            }
        }
    }

 

(2)、prim算法(无向图)

每次选择当前节点所拥有的边中,最小的边,直到所有节点连接在一起。

用set存放已经连在一起的节点,优先队列存放现有节点所有边。每次弹出一个 最小边,若toNote 不在set中,就加入set

    public static Set<Edge> prim(Graph graph) {
        HashSet<Note> set = new HashSet<>();
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>((Edge edge1, Edge edge2) -> edge1.weight - edge2.weight);
        HashSet<Edge> resultSet = new HashSet<>();
        for (Note note : graph.notes.values()) {
            
            if (!set.contains(note)) {
                set.add(note);
                for (Edge edge : note.edges) {
                    priorityQueue.add(edge);
                }
            }

            while (!priorityQueue.isEmpty()) {
                Edge edge = priorityQueue.poll();
                Note toNote = edge.to;
                if (!set.contains(toNote)) {
                    resultSet.add(edge);
                    set.add(toNote);
                    for (Edge edge1 : toNote.edges) {
                        priorityQueue.add(edge1);
                    }
                    break;
                }
            }
        }
        return resultSet;
    }

 

3、拓扑排序(有向无环图)

思路:用map记录每个节点的入度,将入度为0的加入队列中。队列弹出节点,将节点加入结果集,此节点下的每一个节点的入度都减一,并将入度变为0的下节点加入队列中。 

    public static List<Note> tuopuSort(Graph graph) {
        Queue<Note> queue = new LinkedList<>();
        HashMap<Note, Integer> inMap = new HashMap<>();
        for (Note note : graph.notes.values()) {
            inMap.put(note, note.in);
            if (note.in == 0) {
                queue.add(note);
            }
        }
        ArrayList<Note> result = new ArrayList<>();

        while (!queue.isEmpty()) {
            Note cur = queue.poll();
            result.add(cur);
            for (Note next : cur.nexts) {
                inMap.put(next, inMap.get(next) - 1);
                if (inMap.get(next) == 0) {
                    queue.add(next);
                }
            }
        }
        return result;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值