图的表示:如何存储微博、微信等社交网络中的好友关系?
发布网友
发布时间:2022-12-06 15:56
我来回答
共1个回答
热心网友
时间:2024-11-18 23:48
x博中,两个人可以互相关注,互加好友,那如何存储这些社交网络的好友关系呢?
这就要用到:图。
和树比起来,这是一种更加复杂的非线性表结构。
树的元素称为节点,图中元素叫作顶点(vertex)。图中的一个顶点可以与任意其他顶点建立连接关系,这种建立的关系叫作边(edge)。
社交网络就是典型的图结构。
把每个用户看作一个顶点。如果两个用户之间互加好友,就在两者之间建立一条边。
所以,整个微信的好友关系就可用一张图表示。
每个用户有多少个好友,对应到图中就叫作顶点的度(degree),即跟顶点相连接的边的条数。
不过微博的社交关系跟微信还有点不同,更复杂一点。微博允许单向关注,即用户A关注用户B,但B可不关注A。
这就引入边的“方向”。
A关注B,就在图中画一条从A到B的带箭头的边,表示边的方向。A、B互关,就画一条从A指向B的边,再画一条从B指向A的边,这种边有方向的图叫作“有向图”。边没有方向的图也就叫“无向图”。
无向图中有“度”:一个顶点有多少条边。
有向图中,把度分为:
QQ社交关系更复杂,不仅记录用户之间的好友关系,还记录了两个用户之间的亲密度,如何在图中记录这种好友关系亲密度呢?
这就要用到带权图(weighted graph),每条边都有个权重(weight),可以通过这个权重来表示QQ好友间的亲密度。
最直观的一种存储方法,邻接矩阵(Adjacency Matrix)。
依赖一个二维数组:
无向图,若A[i][j]==1,则A[j][i]==1。实际上,只需存储一个即可。即无向图的二维数组,如果将其用对角线划分为上下两部分,则只需利用上或下面这样一半空间就够了,另外一半其实完全浪费。
如果存储的是稀疏图(Sparse Matrix),即顶点很多,但每个顶点的边并不多,则更浪费空间。
如微信有好几亿用户,对应到图就是好几亿顶点。但每个用户好友并不很多,一般也就三五百个而已。如果我们用邻接矩阵来存储,那绝大部分的存储空间都被浪费了。
但这也并不是说,邻接矩阵的存储方法就完全没有优点。首先,邻接矩阵的存储方式简单、直接,因为基于数组,所以在获取两个顶点的关系时,就非常高效。其次,用邻接矩阵存储图的另外一个好处是方便计算。这是因为,用邻接矩阵的方式存储图,可以将很多图的运算转换成矩阵之间的运算。比如求解最短路径问题时会提到一个Floyd-Warshall算法,就是利用矩阵循环相乘若干次得到结果。
针对上面邻接矩阵比较浪费内存空间,另外一种图存储,邻接表(Adjacency List)。
有点像散列表?每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点。图中画的是一个有向图的邻接表存储方式,每个顶点对应的链表里面,存储的是指向的顶点。对于无向图来说,也是类似的,不过,每个顶点的链表中存储的,是跟这个顶点有边相连的顶点,你可以自己画下。
如上图示例,若要确定是否存在一条从顶点2到顶点4的边,就要遍历顶点2的链表,看其中是否存在顶点4,而链表存储对缓存不友好。所以邻接表查询两个顶点之间的关系较为低效。
基于链表法解决冲突的散列表中,若链过长,为提高查找效率,可将链表换成其他更高效数据结构,如平衡二叉查找树。
邻接表长得很像散列。所以,也可将邻接表同散列表一样进行“优化”。
可将邻接表中的链表改成平衡二叉查找树。实际可选用红黑树。即可更快速查找两个顶点之间是否存在边。
这里的二叉查找树也可换成其他动态数据结构,如跳表、散列表。
还可将链表改成有序动态数组,通过二分查找快速定位两个顶点之间是否存在边。
虽然微博有向图,微信是无向图,但对该问题,二者思路类似,以微博为例。
数据结构服务于算法,选择哪种存储方法和需支持的操作有关。
对于微博用户关系,需支持如下操作:
因为社交网络是一张稀疏图,使用邻接矩阵存储比较浪费存储空间。所以,这里采用邻接表。
但一个邻接表存储这种有向图也是不够的。查找某用户关注了哪些用户很容易,但若想知道某用户都被哪些用户关注了,即粉丝列表就没法了。
因此,还需一个逆邻接表,存储用户的被关注关系:
基础的邻接表不适合快速判断两个用户是否为关注与被关注关系,所以进行优化,将邻接表的链表改为支持快速查找的动态数据结构。
因需按照用户名称首字母排序,分页获取用户的粉丝列表或关注列表,跳表最合适:插入、删除、查找都非常高效,时间复杂度 ,空间复杂度稍高,是 。
跳表存储数据先天有序,分页获取粉丝列表或关注列表,非常高效。
对小规模数据,如社交网络中只有几万、几十万个用户,可将整个社交关系存储在内存,该解决方案没问题。
可通过哈希算法等数据分片方案,将邻接表存储在不同机器:
如下图,在机器1上存储顶点1,2,3的邻接表,在机器2上,存储顶点4,5的邻接表。逆邻接表的处理方式也一样。当要查询顶点与顶点关系的时候,我们就利用同样的哈希算法,先定位顶点所在的机器,然后再在相应的机器上查找。
还能借助外部存储(比如硬盘),因为外部存储的存储空间比内存多很多:
如用下表存储这样一个图。为高效支持前面定义的操作,可建多个索引,比如第一列、第二列,给这两列都建立索引。