美文网首页
09.图的表示

09.图的表示

作者: 哈哈大圣 | 来源:发表于2019-10-09 23:33 被阅读0次

    图的表示

    点击这里,前提知晓...

    不考虑自环边和平行边

    • 实现图的接口
    /**
     * 图的接口
     * @author Liucheng
     * @date 2019/10/13 15:48
     */
    public interface Graph {
        public int V();
        public int E();
        public void addEdge( int v , int w );
        boolean hasEdge( int v , int w );
        void show();
        public Iterable<Integer> adj(int v);
    }
    

    一、邻接矩阵 Adjacency Matrix

    使用一个 2x2 的矩阵表示一个图的联通性,标识一个点与所有点的连接信息

    1). 无向图的邻接矩阵表示方法


    无向图邻接矩阵.png

    无向图具有对角线(“\”)对称性,1标识联通,0表示不通

    2). 有向图的邻接矩阵表示方法


    有向图邻接矩阵.png

    1标识联通,0表示不通

    3). 邻接矩阵适合表示稠密图Dense Graph


    稠密图与完全图.png

    完全图就是每个节点之间都进行相连

    4). 使用邻接矩阵实现稠密图

    import java.util.Vector;
    
    /**
     * 稠密图 - 邻接矩阵;
     * 不考虑自环边、平行边和删除节点
     * @author Liucheng
     * @since 2019-10-09
     */
    public class DenseGraph implements Graph {
        /**
         * 图的节点数
         */
        private int n;
        /**
         * 图的边数
         */
        private int m;
        /**
         * 是否为有向图,true有向图,false无向图
         */
        private boolean directed;
        /**
         * 图的具体数据
         */
        private boolean[][] g;
    
        /**
         * 构造函数
         */
        public DenseGraph(int n, boolean directed) {
            assert n >= 0;
            this.n = n;
            // 初始化时没有任何边
            this.m = 0;
            this.directed = directed;
            /*
            * g的初始化为n*n的布尔矩阵,每一个g[i][j]均为false,表示没有任何边
            * false为布尔类型变量的默认值 */
            this.g = new boolean[n][n];
        }
    
        /**
         * 返回节点个数
         */
        @Override
        public int V() {return n;}
    
        /**
         * 返回边的个数
         */
        @Override
        public int E() {return m;}
    
        /**
         * 向图中添加一个连接,也就是一条边
         */
        @Override
        public void addEdge(int v, int w) {
    
            if (this.hasEdge(v, w)) {
                return;
            }
    
            g[v][w] = true;
    
            // 如果为无向图,由于对称性,需要进行设置
            if (!directed) {
                g[w][v] = true;
            }
    
            m++;
        }
    
        /**
         * 验证图中是否有从v到w的边
         */
        @Override
        public boolean hasEdge(int v, int w) {
            // 不能越界
            assert (v >= 0 && v < n);
            assert (w >= 0 && w < n);
    
            return g[v][w];
        }
    
        /**
         * 返回图中一个顶点的所有邻边,
         * 由于java使用引用机制,返回一个Vector不会带来额外的开销
         * 可以使用java变准库中提供的迭代器
         */
        @Override
        public Iterable<Integer> adj(int v) {
            assert v >= 0 && v < n;
            Vector<Integer> adjV = new Vector<>();
            for (int i = 0; i < n; i++) {
                if (g[v][i]) {
                    adjV.add(i);
                }
            }
    
            return adjV;
        }
    
        /**
         * 显示图的信息
         */
        @Override
        public void show() {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    System.out.print((g[i][j] ? 1 : 0) + "\t");
                }
                System.out.println();
            }
        }
    }
    

    二、邻接表 Adjacency Lists

    使用一个列表标识只与自己连接的节点信息

    1). 无向图的邻接矩阵表示方法


    无向图邻接表.png

    2). 有向图的邻接矩阵表示方法


    有向图邻接表.png

    3). 邻接表适合表示稀疏图Sparse Graph


    稀疏图.png

    4). 使用邻接表实现稀疏图

    import java.util.*;
    
    /**
     * 稀疏图 - 邻接表:
     * 不考虑自环边、平行边和删除节点情况
     * @author Liucheng
     * @since 2019-10-09
     */
    public class SparseGraph implements Graph {
        /**
         * 图的节点数
         */
        private int n;
        /**
         * 图的边数
         */
        private int m;
        /**
         * 是否为有向图,true表示有向图;false表示无向图
         */
        private boolean directed;
        /**
         * 具体的图数据
         * 邻接矩阵 true代表有边,false代表没有边
         */
        Vector<Integer>[] g;
    
        /**
         * 构造函数
         */
        public SparseGraph(int n, boolean directed) {
            assert n >= 0;
            this.n = n;
            // 初始化时没有任何边
            this.m = 0;
            this.directed = directed;
            /* g初始化为n个空的vector,
            * 表示每一个g[i]都为空,即没有任何边*/
            this.g = (Vector<Integer>[]) new Vector[n];
    
            for (int i = 0; i < n; i++) {
                g[i] = new Vector<Integer>();
            }
        }
    
        /**
         * 返回节点的个数
         */
        @Override
        public int V() {return n;}
    
        /**
         * 返回边的个数
         */
        @Override
        public int E() {return m;}
    
        /**
         * 向图中添加一个边
         */
        @Override
        public void addEdge(int v, int w) {
            assert v >= 0 && v < n;
            assert w >= 0 && w < n;
    
            g[v].add(w);
    
            // 不是自环边且为无向图
            if (v != w && !directed) {
                g[w].add(v);
            }
    
            m++;
        }
    
        /**
         * 验证图中是否有从v到w的边
         */
        @Override
        public boolean hasEdge(int v, int w) {
            assert (v >= 0 && v < n);
            assert (w >= 0 && w < n);
    
            return g[v].contains(w);
        }
    
        /**
         * 返回图中一个顶点的所有邻边
         */
        @Override
        public Iterable<Integer> adj(int v) {
            assert v >= 0 && v < n;
            return g[v];
        }
    
        @Override
        public void show() {
            for (int i = 0; i < n; i++) {
                System.out.print("vertex " + i + ":\t");
                for (int j = 0; j < g[i].size(); j++) {
                    System.out.print(g[i].elementAt(j) + "\t");
                }
                System.out.println();
            }
        }
    }
    

    三、测试

    1). 准备的文件内容 (maven工程的resources目录下)

    1. testG1.txt
    13 13
    0 5
    4 3
    0 1
    9 12
    6 4
    5 4
    0 2
    11 12
    9 10
    0 6
    7 8
    9 11
    5 3
    
    
    1. testG2.txt
    6 8
    0 1
    0 2
    0 5
    1 2
    1 3
    1 4
    3 4
    3 5
    
    

    2). 文件读取工具类

    import java.io.*;
    import java.util.InputMismatchException;
    import java.util.Locale;
    import java.util.NoSuchElementException;
    import java.util.Scanner;
    
    /**
     * @author Liucheng
     * @since 2019-10-13
     */
    public class ReadGraph {
        private Scanner scanner;
    
        public ReadGraph(Graph graph, String filename){
    
            readFile(filename);
    
            try {
                int V = scanner.nextInt();
                if (V < 0) {
                    throw new IllegalArgumentException("number of vertices in a Graph must be nonnegative");
                }
                assert V == graph.V();
    
                int E = scanner.nextInt();
                if (E < 0) {
                    throw new IllegalArgumentException("number of edges in a Graph must be nonnegative");
                }
    
                for (int i = 0; i < E; i++) {
                    int v = scanner.nextInt();
                    int w = scanner.nextInt();
                    assert v >= 0 && v < V;
                    assert w >= 0 && w < V;
                    graph.addEdge(v, w);
                }
            }
            catch (InputMismatchException e) {
                String token = scanner.next();
                throw new InputMismatchException("attempts to read an 'int' value from input stream, but the next token is \"" + token + "\"");
            }
            catch (NoSuchElementException e) {
                throw new NoSuchElementException("attemps to read an 'int' value from input stream, but there are no more tokens available");
            }
        }
    
        private void readFile(String filename){
            assert filename != null;
            try {
                File file = new File(filename);
                if (file.exists()) {
                    FileInputStream fis = new FileInputStream(file);
                    scanner = new Scanner(new BufferedInputStream(fis), "UTF-8");
                    scanner.useLocale(Locale.ENGLISH);
                } else {
                    throw new IllegalArgumentException(filename + "doesn't exist.");
                }
            }
            catch (IOException ioe) {
                throw new IllegalArgumentException("Could not open " + filename, ioe);
            }
        }
    }
    

    3). 测试方法

    /**
     * 创建图测试
     */
    @Test
    public void createGraph() {
        // 使用两种图的存储方式读取testG1.txt文件
        String filename = Thread.currentThread().getContextClassLoader().getResource("testG1.txt").getPath();
        SparseGraph g1 = new SparseGraph(13, false);
        ReadGraph readGraph1 = new ReadGraph(g1, filename);
        System.out.println("test G1 in Sparse Graph:");
        g1.show();
    
        System.out.println();
    
        DenseGraph g2 = new DenseGraph(13, false);
        ReadGraph readGraph2 = new ReadGraph(g2 , filename );
        System.out.println("test G1 in Dense Graph:");
        g2.show();
    
        System.out.println();
    
        // 使用两种图的存储方式读取testG2.txt文件
        filename = Thread.currentThread().getContextClassLoader().getResource("testG2.txt").getPath();
        SparseGraph g3 = new SparseGraph(6, false);
        ReadGraph readGraph3 = new ReadGraph(g3, filename);
        System.out.println("test G2 in Sparse Graph:");
        g3.show();
    
        System.out.println();
    
        DenseGraph g4 = new DenseGraph(6, false);
        ReadGraph readGraph4 = new ReadGraph(g4, filename);
        System.out.println("test G2 in Dense Graph:");
        g4.show();
    }
    
    • 运行结果
    test G1 in Sparse Graph:
    vertex 0:   5   1   2   6   
    vertex 1:   0   
    vertex 2:   0   
    vertex 3:   4   5   
    vertex 4:   3   6   5   
    vertex 5:   0   4   3   
    vertex 6:   4   0   
    vertex 7:   8   
    vertex 8:   7   
    vertex 9:   12  10  11  
    vertex 10:  9   
    vertex 11:  12  9   
    vertex 12:  9   11  
    
    test G1 in Dense Graph:
    0   1   1   0   0   1   1   0   0   0   0   0   0   
    1   0   0   0   0   0   0   0   0   0   0   0   0   
    1   0   0   0   0   0   0   0   0   0   0   0   0   
    0   0   0   0   1   1   0   0   0   0   0   0   0   
    0   0   0   1   0   1   1   0   0   0   0   0   0   
    1   0   0   1   1   0   0   0   0   0   0   0   0   
    1   0   0   0   1   0   0   0   0   0   0   0   0   
    0   0   0   0   0   0   0   0   1   0   0   0   0   
    0   0   0   0   0   0   0   1   0   0   0   0   0   
    0   0   0   0   0   0   0   0   0   0   1   1   1   
    0   0   0   0   0   0   0   0   0   1   0   0   0   
    0   0   0   0   0   0   0   0   0   1   0   0   1   
    0   0   0   0   0   0   0   0   0   1   0   1   0   
    
    test G2 in Sparse Graph:
    vertex 0:   1   2   5   
    vertex 1:   0   2   3   4   
    vertex 2:   0   1   
    vertex 3:   1   4   5   
    vertex 4:   1   3   
    vertex 5:   0   3   
    
    test G2 in Dense Graph:
    0   1   1   0   0   1   
    1   0   1   1   1   0   
    1   1   0   0   0   0   
    0   1   0   0   1   1   
    0   1   0   1   0   0   
    1   0   0   1   0   0   
    

    相关文章

      网友评论

          本文标题:09.图的表示

          本文链接:https://www.haomeiwen.com/subject/zwbnpctx.html