探秘 Redis 跳跃列表

跳跃列表(skiplist)是一种有序的数据结构,它通过在每个节点维护多个指向其他节点的指针,我们可以平均O(logN) 的时间复杂度快速访问节点,大部分情况下它的性能可以和平衡树相媲美,不过实现起来更为简单。

跳跃列表是 Redis 中有序集合的一种实现方式,在有序集合的元素数量较多或者是元素成员长度较长时,Redis 就会使用跳跃列表加字典来存储元素。

大家都知道 zset 每一个 value 都有一个 score ,zset 根据每个 value 的 score 将其排序,并且元素不会重复,那么,为了能通过每个元素的 value 快速得到对应的 score ,zset 的存储结构里就需要字典来做这么一个映射。

而跳跃列表,用于通过score 快速地定位 value。

跳跃列表实现

Redis 中的跳跃列表由 zskiplistNode 结构(表示跳跃列表节点)和 zskiplist(用于保存跳跃列表相关信息)构成。

zskiplistNode

typedef struct zskiplistNode {
	// 层
	struct zskiplistLevel {
		// 前进指针
		struct zskiplistNode *forward;
		// 跨度
		unsigned int span;
	} level[];
	// 后退指针
	struct zskiplistNode *backward;
	// 分值
	double score;
	// 成员对象
	robj *obj;
} zskiplistNode;

zskiplist

typedef struct zskiplist {
	// 表头节点和表尾节点
	struct zskiplistNode *header,*tail;
	// 表中节点的数量
	unsigned long length;
	// 表中的最大层数
	int level;
}zskiplist;

下面展示了一个跳跃列表
在这里插入图片描述
Redis 的跳跃列表共有 64 层,意味着最多可以容纳 2^64 次方个元素。

最左边的是一个zskiplist 结构:
header 指针和 tail 指针分别指向跳跃列表表头和表尾节点,length 记录节点的数量,这里为3(表头节点不算),level 记录表中最后的层数,这里为4(表头节点不算)

右边四个是 zskiplistNode 结构:
每个层都有两个属性,前进指针和跨度,前进指针用于访问位于表尾方向和该层层数相同的节点(没有则指向NULL),跨度记录了前进指针指向节点和当前节点的距离,也就是表示了中间经过了多少个节点,图上箭头中的数字表示跨度。
后退指针(图中的BW)指向当前节点的前一个节点,用于反向遍历。
分值:跳跃表中节点按分值从小到大排序,图中三个节点分值为3.0,4.0,5.0
成员对象:即和分值所对应的value,本质上是一个SDS对象

随机层数

跳跃列表节点的 level 数组是可以包含多个元素的,每个元素都包含一个指向其他节点的指针,而这个层数是在创建一个节点时,Redis 根据幂次定律随机生成的。

最后,再说明一点,zset 虽然使用了字典加跳跃列表两种数据结构来保存数据,但是实际上字典和跳跃列表是共享 value 和 score 的,即由指针指向了同一个对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值