热门搜索:软件下载

怎么存储微博好友关系(如何设计存储社交平台好友关系的数据结构)

首页教程怎么存储微博好友关系更新时间:2023-05-20 17:14:28

x博中,两个人可以互相关注,互加好友,那如何存储这些社交网络的好友关系呢?

这就要用到:图。

什么是“图”?(Graph)

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

树的元素称为节点,图中元素叫作顶点(vertex)。图中的一个顶点可以与任意其他顶点建立连接关系,这种建立的关系叫作边(edge)。

怎么存储微博好友关系,如何设计存储社交平台好友关系的数据结构(1)

社交网络就是典型的图结构。

把每个用户看作一个顶点。如果两个用户之间互加好友,就在两者之间建立一条边。 所以,整个微信的好友关系就可用一张图表示。 每个用户有多少个好友,对应到图中就叫作顶点的度(degree),即跟顶点相连接的边的条数。

不过微博的社交关系跟微信还有点不同,更复杂一点。微博允许单向关注,即用户A关注用户B,但B可不关注A。

如何用图表示这种单向社交关系呢?

这就引入边的“方向”。

A关注B,就在图中画一条从A到B的带箭头的边,表示边的方向。A、B互关,就画一条从A指向B的边,再画一条从B指向A的边,这种边有方向的图叫作“有向图”。边没有方向的图也就叫“无向图”。

怎么存储微博好友关系,如何设计存储社交平台好友关系的数据结构(2)

无向图中有“度”:一个顶点有多少条边。 有向图中,把度分为:

  • 入度(In-degree) 有多少条边指向这个顶点,即有多少粉丝
  • 出度(Out-degree) 有多少条边是以这个顶点为起点指向其他顶点。对应到微博的例子,即关注了多少人

QQ社交关系更复杂,不仅记录用户之间的好友关系,还记录了两个用户之间的亲密度,如何在图中记录这种好友关系亲密度呢? 这就要用到带权图(weighted graph),每条边都有个权重(weight),可以通过这个权重来表示QQ好友间的亲密度。

怎么存储微博好友关系,如何设计存储社交平台好友关系的数据结构(3)

存储邻接矩阵存储方法

最直观的一种存储方法,邻接矩阵(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),即顶点很多,但每个顶点的边并不多,则更浪费空间。 如微信有好几亿用户,对应到图就是好几亿顶点。但每个用户好友并不很多,一般也就三五百个而已。如果我们用邻接矩阵来存储,那绝大部分的存储空间都被浪费了。

但这也并不是说,邻接矩阵的存储方法就完全没有优点。首先,邻接矩阵的存储方式简单、直接,因为基于数组,所以在获取两个顶点的关系时,就非常高效。其次,用邻接矩阵存储图的另外一个好处是方便计算。这是因为,用邻接矩阵的方式存储图,可以将很多图的运算转换成矩阵之间的运算。比如求解最短路径问题时会提到一个Floyd-Warshall算法,就是利用矩阵循环相乘若干次得到结果。

邻接表存储方法

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

有点像散列表?每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点。图中画的是一个有向图的邻接表存储方式,每个顶点对应的链表里面,存储的是指向的顶点。对于无向图来说,也是类似的,不过,每个顶点的链表中存储的,是跟这个顶点有边相连的顶点,你可以自己画下。

怎么存储微博好友关系,如何设计存储社交平台好友关系的数据结构(4)

  • 邻接矩阵存储较浪费空间,但更省时
  • 邻接表较节省存储空间,但较耗时

如上图示例,若要确定是否存在一条从顶点2到顶点4的边,就要遍历顶点2的链表,看其中是否存在顶点4,而链表存储对缓存不友好。所以邻接表查询两个顶点之间的关系较为低效。

基于链表法解决冲突的散列表中,若链过长,为提高查找效率,可将链表换成其他更高效数据结构,如平衡二叉查找树。 邻接表长得很像散列。所以,也可将邻接表同散列表一样进行“优化”。

可将邻接表中的链表改成平衡二叉查找树。实际可选用红黑树。即可更快速查找两个顶点之间是否存在边。 这里的二叉查找树也可换成其他动态数据结构,如跳表、散列表。 还可将链表改成有序动态数组,通过二分查找快速定位两个顶点之间是否存在边。

如何存储微博、微信等社交网络中的好友关系?

虽然微博有向图,微信是无向图,但对该问题,二者思路类似,以微博为例。

数据结构服务于算法,选择哪种存储方法和需支持的操作有关。 对于微博用户关系,需支持如下操作:

  • 判断用户A是否关注了用户B
  • 判断用户A是否是用户B的粉丝
  • 用户A关注用户B
  • 用户A取消关注用户B
  • 根据用户名称的首字母排序,分页获取用户的粉丝列表
  • 根据用户名称的首字母排序,分页获取用户的关注列表

因为社交网络是一张稀疏图,使用邻接矩阵存储比较浪费存储空间。所以,这里采用邻接表。

但一个邻接表存储这种有向图也是不够的。查找某用户关注了哪些用户很容易,但若想知道某用户都被哪些用户关注了,即粉丝列表就没法了。

因此,还需一个逆邻接表,存储用户的被关注关系:

  • 邻接表,每个顶点的链表中,存储的就是该顶点指向的顶点 查找某个用户关注了哪些用户
  • 逆邻接表,每个顶点的链表中,存储的是指向该顶点的顶点 查找某个用户被哪些用户关注

基础的邻接表不适合快速判断两个用户是否为关注与被关注关系,所以进行优化,将邻接表的链表改为支持快速查找的动态数据结构。

那是红黑树、跳表、有序动态数组还是散列表呢?

因需按照用户名称首字母排序,分页获取用户的粉丝列表或关注列表,跳表最合适:插入、删除、查找都非常高效,时间复杂度$O(logn)$,空间复杂度稍高,是$O(n)$。 跳表存储数据先天有序,分页获取粉丝列表或关注列表,非常高效。

对小规模数据,如社交网络中只有几万、几十万个用户,可将整个社交关系存储在内存,该解决方案没问题。

但像微博上亿用户,数据量太大,无法全部存储在内存,何解?

可通过哈希算法等数据分片方案,将邻接表存储在不同机器:

  • 机器1存储顶点1,2,3的邻接表
  • 机器2存储顶点4,5的邻接表 逆邻接表的处理方式同理。

当要查询顶点与顶点关系时,利用同样的哈希算法,先定位顶点所在机器,然后再在相应机器上查找。

怎么存储微博好友关系,如何设计存储社交平台好友关系的数据结构(5)

还能借助外部存储(比如硬盘),因为外部存储的存储空间比内存多很多: 如用下表存储这样一个图。为高效支持前面定义的操作,可建多个索引,比如第一列、第二列,给这两列都建立索引。

怎么存储微博好友关系,如何设计存储社交平台好友关系的数据结构(6)

参考

https://chowdera.com/2021/03/20210326155939001z.html

https://www.zhihu.com/question/20216864

,