数据结构与算法——图

1. 什么是图?

前面说完了树这种数据结构,接下来在看看一种更加复杂的非线性数据结构——图。

先看看下面图这种数据结构的图片演示吧:

数据结构与算法——图

像上图这样的数据结构就叫做图了,图中的每个节点叫做 顶点 ,各个顶点之间的连接关系叫做 边 ,每个顶点有多少条边,叫做这个顶点的 度 。其实图这种数据结构比较适合用来存储我们常用的微信、微博好友关系。例如存储微信好友,例如两个人互加了微信,就相当于在两个顶点之间加上一条边,而顶点的度则表示一个人有多少微信好友。

而微博这样的存储关系,要稍微复杂一些,因为微博允许当方面关注,例如 A 关注了 B ,而 B 可以不关注 A,这样的关系,我们可以在图中引入方向的概念,先看下图:

数据结构与算法——图

例如 A 关注了 B,那么直接将 A 的边指向 B 即可。这样有方向关系的图,叫做 有向图 ,显然,没有方向关系的图,就叫做 无向图 。

无向图中有度的概念,表示一个顶点有多少条边,而有向图中的度,则还有 入度 和 出度 的区分,例如 A 指向 B,叫做 A 顶点的出度,E 指向了 A,叫做 A 的入度。不难理解,对应到微博的关系中,一个顶点的出度,就表示他关注了多少人,入度,则表示他有多少粉丝。

2. 图是如何存储的?

图有两种存储的方式,第一种叫做邻接矩阵,其底层是利用二维数组来存储的。对于无向图,如果顶点 i 和 j 之间有边,则在二维数组中 A[i] [j] 和 A[j] [i] 位置处标记为 1 ,对于有向图,如果 i 指向了 j,则将二维数组中 A[i] [j] 位置标记为 1,类似,如果 j 指向了 i,则将二维数组中 A[j] [i] 位置标记为 1。看下图的说明就很容易明白了:

数据结构与算法——图

这种存储方式虽然支持较为高效的查找操作,因为可以直接根据数组下标取出数据,但是存在的问题便是比较浪费存储空间,特别是对于数据量较大的情况。

另一种更加常用的图存储方式是邻接表,每个顶点对应一个链表,就像下图这样:

数据结构与算法——图

上面是使用的有向图,每个顶点对应的链表存储的是该顶点所指向的顶点,如果是无向图的话,那就更简单了,每个顶点链表存储的是与该顶点有边关系的顶点。

3. 简单实现一个图

接下来我是用代码简单使用了一个图,你可以看看,顺便理解一下:

public class Graph {
    private int vertex;//图中的顶点个数
    private LinkedList<Integer>[] list;

    public Graph(int vertex) {
        this.vertex = vertex;
        list = new LinkedList[vertex];
        for (int i = 0; i < vertex; i++) {
            list[i] = new LinkedList();
        }
    }

    //两个顶点之间建立边关系
    public void addSide(int v1, int v2){
        if (v1 >= vertex || v2 >= vertex || v1 == v2) return;
        if (!list[v1].contains(v2))
            list[v1].add(v2);
        if (!list[v2].contains(v1))
            list[v2].add(v1);
    }

    //删除顶点之间的边
    public void removeSide(int v1, int v2){
        if (v1 >= vertex || v2 >= vertex || v1 == v2) return;
        if (list[v1].contains(v2))
            list[v1].remove(v2);
        if (list[v2].contains(v1))
            list[v2].remove(v1);
    }

    //列出与某顶点有边关系的所有顶点
    public void listVertexes(int v){
        if (v >= vertex) return;
        System.out.println(list[v].toString());
    }
}

相关推荐