八、基本数据结构(图形结构)

一、理解 “图”

图(Graph)。和树比起来,这是一种更加复杂的非线性表结构。

树中的元素称为节点,图中的元素叫作顶点(vertex)

如下图所示,图中的一个顶点可以与任意其他顶点建立连接关系。这种建立的关系叫作边(edge)

图

举个例子

微信:

比如在微信中可以把每个用户看作一个顶点。

如果两个用户之间互加好友,那就在两者之间建立一条边。

所以,整个微信的好友关系就可以用一张图来表示。其中,每个用户有多少个好友,对应到图中,就叫作顶点的度(degree),就是跟顶点相连接的边的条数

微博:

微博的社交关系跟微信有点不一样,或者说更加复杂一点。

微博允许单向关注,也就是说,用户 A 关注了用户 B,但用户 B 可以不关注用户 A。

可以把图结构稍微改造一下,引入边的“方向”的概念。

如果用户 A 关注了用户 B,就在图中画一条从 A 到 B 的带箭头的边,来表示边的方向。

如果用户 A 和用户 B 互相关注了,那就画一条从 A 指向 B 的边,再画一条从 B 指向 A 的边。

把这种边有方向的图叫作“有向图”。以此类推,把边没有方向的图叫作“无向图”

图

无向图中有“度”这个概念,表示一个顶点有多少条边。在有向图中,把度分为入度(In-degree)和出度(Out-degree)

顶点的入度,表示有多少条边指向这个顶点;顶点的出度,表示有多少条边是以这个顶点为起点指向其他顶点。

对应到微博的例子,入度就表示有多少粉丝,出度就表示关注了多少人。

QQ:

QQ 中的社交关系要更复杂的一点。QQ 不仅记录了用户之间的好友关系,还记录了两个用户之间的亲密度。

如果两个用户经常往来,那亲密度就比较高;如果不经常往来,亲密度就比较低。

要用到另一种图, 带权图(weighted graph)

带权图中,每条边都有一个权重(weight),可以通过这个权重来表示 QQ 好友间的亲密度。

带权图

二、邻接矩阵存储方法

图最直观的一种存储方法就是, 邻接矩阵(Adjacency Matrix)

邻接矩阵的底层依赖一个二维数组

对于无向图来说,如果顶点 i 与顶点 j 之间有边,就将 A[i][j] 和 A[j][i] 标记为 1;

对于有向图来说,如果顶点 i 到顶点 j 之间有一条箭头从顶点 i 指向顶点 j 的边,那就将 A[i][j] 标记为 1。

同理,如果有一条箭头从顶点 j 指向顶点 i 的边,就将 A[j][i] 标记为 1。

对于带权图,数组中就存储相应的权重。

邻接矩阵

用邻接矩阵来表示一个图,虽然简单、直观,但是比较浪费存储空间

因为对于无向图来说,如果 A[i][j] 等于 1,那 A[j][i] 也肯定等于 1。实际上,只需要存储一个就可以了。

也就是说,无向图的二维数组中,如果将其用对角线划分为上下两部分,那只需要利用上面或者下面这样一半的空间就足够了,另外一半白白浪费掉了。

还有,如果存储的是稀疏图(Sparse Matrix),也就是说,顶点很多,但每个顶点的边并不多,那邻接矩阵的存储方法就更加浪费空间了。

比如微信有好几亿的用户,对应到图上就是好几亿的顶点。但是每个用户的好友并不会很多,一般也就三五百个而已。如果用邻接矩阵来存储,那绝大部分的存储空间都被浪费了。

邻接矩阵的存储方法的优点

首先,邻接矩阵的存储方式简单、直接,因为基于数组,所以在获取两个顶点的关系时,就非常高效。

其次,用邻接矩阵存储图的另外一个好处是方便计算。这是因为,用邻接矩阵的方式存储图,可以将很多图的运算转换成矩阵之间的运算。

三、邻接表存储方法

针对上面邻接矩阵比较浪费内存空间的问题,来看另外一种图的存储方法,邻接表(Adjacency List)。

邻接表有点像散列表,每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点

图中画的是一个有向图的邻接表存储方式,每个顶点对应的链表里面,存储的是指向的顶点。

对于无向图来说,也是类似的,不过,每个顶点的链表中存储的,是跟这个顶点有边相连的顶点。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyygyy.html