数据结构(四)——图的存储

图的一些算法比较复杂,这里分多个博客进行总结

图的相关概念

其实之前的几种数据结构,其实比较简单,之前的记忆还比较清晰,但是到图这个地方,有些概念就有些模糊了,这里还是现在总结一下图的相关概念。

定义

定义:图(graph)是由一些点(vertex)和这些点之间的连线(edge)所组成的;其中,点通常被成为"顶点(vertex)",而点与点之间的连线则被成为"边或弧"(edege)。通常记为,G=(V,E)。

根据边是否有方向,可以分为有向图和无向图

无向图

在这里插入图片描述

有向图

在这里插入图片描述

邻接点和度

邻接点

一条边上的两个顶点叫做邻接点。
例如,上面无向图G0中的顶点A和顶点C就是邻接点。

在有向图中,除了邻接点之外;还有"入边"和"出边"的概念。
顶点的入边,是指以该顶点为终点的边。而顶点的出边,则是指以该顶点为起点的边。
*例如,上面有向图G2中的BE是邻接点;***B的出边,还是E的入边。

在无向图中,某个顶点的度是邻接到该顶点的边(或弧)的数目。
例如,上面无向图G0中顶点A的度是2

在有向图中,度还有"入度"和"出度"之分。
某个顶点的入度,是指以该顶点为终点的边的数目。而顶点的出度,则是指以该顶点为起点的边的数目。
顶点的度=入度+出度。
例如,上面有向图G2中,顶点B的入度是2,出度是3;顶点B的度*=2+3=5**。*

图的存储方式

邻接矩阵

邻接矩阵是指用矩阵来表示图。它是采用矩阵来描述图中顶点之间的关系(及弧或边的权)。
假设图中顶点数为n,则邻接矩阵定义为:

在这里插入图片描述

通常采用两个数组来实现邻接矩阵:一个一维数组用来保存顶点信息,一个二维数组来用保存边的信息。
邻接矩阵的缺点就是比较耗费空间。

无向图的邻接矩阵

在这里插入图片描述

相关代码设计

public class MatrixDG {
    int size;
    char[] vertexs; //图顶点名称
    int[][] matrix; //图关系矩阵
}

具体的构建方法

/**
 * autor:liman
 * createtime:2020/2/9
 * comment: 无向图的数组表示
 */
public class MatrixNDG {

    int size;
    char[] vertexs; //图顶点名称
    int[][] matrix; //图关系矩阵

    public MatrixNDG(char[] vertexs, char[][] edges) {
        size = vertexs.length;
        matrix = new int[size][size];
        this.vertexs = vertexs;

        for (char[] c : edges) {
            int p1 = getPosition(c[0]);
            int p2 = getPosition(c[1]);

            //无向图,两个对称的位置都需要存储
            matrix[p1][p2] = 1;
            matrix[p2][p1] = 1;
        }
    }

    public void print() {
        for (int[] i : matrix) {
            for (int j : i) {
                System.out.print(j + " ");
            }
            System.out.println();
        }
    }

    //根据顶点名称获取对应的矩阵下标
    private int getPosition(char ch) {
        for (int i = 0; i < vertexs.length; i++) {
            if (vertexs[i] == ch) {
                return i;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'};
        char[][] edges = new char[][]{
                {'A', 'C'},
                {'A', 'D'},
                {'A', 'F'},
                {'B', 'C'},
                {'C', 'D'},
                {'E', 'G'},
                {'D', 'G'},
                {'I', 'J'},
                {'J', 'G'},
                {'E', 'H'},
                {'H', 'K'}};

        MatrixNDG matrixNDG = new MatrixNDG(vexs,edges);
        matrixNDG.print();
    }
}

有向图的邻接矩阵

在这里插入图片描述

有向图的构建存储结构与上面一致,只是在构造的时候少一行代码,具体如下:

public MatrixDG(char[] vertexs, char[][] edges) {
    size = vertexs.length;
    matrix = new int[size][size];
    this.vertexs = vertexs;

    for (char[] c : edges) {
        int p1 = getPosition(c[0]);
        int p2 = getPosition(c[1]);

        //有向图,只需要存储一个即可
        matrix[p1][p2] = 1;
    }
}

邻接表

邻接表是图的一种链式存储表示方法。它是改进后的"邻接矩阵",它的缺点是不方便判断两个顶点之间是否有边,但是相对邻接矩阵来说更省空间。

无向图的邻接表

在这里插入图片描述

具体的存储设计

/**
 * autor:liman
 * createtime:2020/2/9
 * comment: 邻接表的方式存储无向图
 */
public class ListNDG {

    Vertex[] vertexList;	//这里就是一个存储节点的数组
    int size;

    class Vertex{
        char ch;
        Vertex next;

        public Vertex(char ch) {
            this.ch = ch;
        }

        void add(char ch){
            Vertex node = this;
            while(node.next!=null){//找到链表结尾
                node = node.next;
            }
            node.next = new Vertex(ch);
        }
    }
}

具体的构建操作如下:

public ListNDG(char[] vertexs,char[][] edgs){
    size = vertexs.length;
    this.vertexList = new Vertex[size];//确定邻接表的大小
    //设置邻接表的每一个节点
    for(int i = 0;i<size;i++){
        this.vertexList[i] = new Vertex(vertexs[i]);
    }

    //存储边的信息
    for(char[] c:edgs){
        int p1 = getPosition(c[0]);
        vertexList[p1].add(c[1]);
        int p2 = getPosition(c[1]);
        vertexList[p2].add(c[0]);
    }
}

//根据顶点名称获取链表下标
private int getPosition(char ch){
    for(int i =0;i<size;i++){
        if(vertexList[i].ch==ch){
            return i;
        }
    }
    return -1;
}

public void print(){
    for(int i = 0;i<size;i++){
        Vertex temp = vertexList[i];
        while(temp!=null){
            System.out.print(temp.ch+" ");
            temp = temp.next;
        }
        System.out.println();
    }
}

public static void main(String[] args) {
    char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'};
    char[][] edges = new char[][]{
            {'A', 'C'},
            {'A', 'D'},
            {'A', 'F'},
            {'B', 'C'},
            {'C', 'D'},
            {'E', 'G'},
            {'D', 'G'},
            {'I', 'J'},
            {'J', 'G'},
            {'E', 'H'},
            {'H', 'K'}};

    ListNDG listNDG = new ListNDG(vexs,edges);
    listNDG.print();
}

有向图的邻接表

在这里插入图片描述

与邻接矩阵的方式一样,与无向图就差两行代码

public ListDG(char[] vertexs, char[][] edgs){
    size = vertexs.length;
    this.vertexList = new Vertex[size];//确定邻接表的大小
    //设置邻接表的每一个节点
    for(int i = 0;i<size;i++){
        this.vertexList[i] = new Vertex(vertexs[i]);
    }

    //存储边的信息,这里是有向图只存储单向的连接边信息
    for(char[] c:edgs){
        int p1 = getPosition(c[0]);
        vertexList[p1].add(c[1]);
    }
}
发布了133 篇原创文章 · 获赞 37 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/liman65727/article/details/104240535