您的位置:首页 > 理论基础 > 数据结构算法

Redis数据结构之跳跃表-skiplist

2020-02-29 18:34 316 查看

Redis
中,
zset
是一个复合结构:

  • 使用

    hash
    来存储
    value
    score
    的映射关系

  • 使用跳跃表来提供按照

    score
    进行排序的功能,同时可以指定
    score
    范围来获取
    value
    列表

结构

zset
内部是一个
hash
字典加一个跳跃表
skiplist

struct zslnode {
string value;
double score;
zslnode *[]forwards; // 多层连接指针
zslnode *backward    // 回溯指针
} zslnode;
​
struct zsl {
zslnode *header;          // 跳跃表头指针
int maxLevel;             // 跳跃表当前最高层
map<string, zslnode*> ht; // hash结构的所有键值对
} zsl;

图为跳跃表示意图,实际上在

Redis
中共有
64
层,即最多可容纳
2^64
个元素。

每一个

kv
块即代码中
zslnode
header
value
NULL
值,
score
Double.MIN_VALUE
kv
之间使用指针链接成为双向链表,这些键值对根据
score
进行有序排列,不同的
kv
层高可能不同,层数越高则
kv
越少,同一层的
kv
之间使用指针进行串接,对于每一层的元素的遍历都是从
kv header
出发的。

常用操作

查找

如图所示,需要定位紫色的

kv
时,首先从
header
最高层开始进行遍历,遍历到第一个比
k
值小的节点,然后下降一层继续查找该层最后一个比
k
小的元素,依此类推,直到查找到该元素为止。

搜索时中间的一系列节点称之为搜索路径,它是从最高层一直到最底层的每一层最后一个比目标节点小的元素节点列表。

插入

插入新节点时,首先需要搜索合适的插入点,类似于查找过程找到合适节点之后就可以开始创建新的节点。创建时需要为节点随机分配一个层数,再将搜索路径上的节点和新节点通过前后指针进行串接。

如果分配的新的节点比当前跳跃表最大高度高的话,需要更新一下跳跃表的最大高度。

删除

删除过程和插入过程类似,需要先将搜索路径找出来,然后对于每一个层的相关节点,都需要重排一下前后指针,同时注意更新一下最高层数

maxLevel

更新

调用

zadd
方法时,如果对应的
value
不存在,直接进行插入;如果已经存在且只是更新
score
的话,需要进行更新。

如果新值的

score
不会带来排序位置的改变,则不需要调整位置,直接修改元素的
score
值即可,否则需要调整该节点位置。

Redis
在更新节点位置时,采用先删除这个元素,再插入这个元素的方法,这样就不需要判断是否需要调整位置,只需要进行两次路径搜索即可。

如果
score
值一样

极端情况下,

zset
中所有元素的
score
一样,此时查找性能也不会退化为
O(n)
,因为
zset
的排序不只考虑
score
,如果
score
一样的话还会再比较
value
值。

计算元素排名

zset
可以使用
rank
获取元素排名,主要是因为
Redis
中,对于
skiplist
的节点的
forward
指针进行了优化,给每一个
forward
指针添加了
span
属性,表示从前一个节点沿当前层的
forward
指针跳到当前节点时中间会跳过多少个节点。

借助

span
属性,在计算一个元素的排名时,只需要将搜索路径上经过的所有节点的
span
属性进行叠加即可计算出最终的
rank
值。

转载于:https://www.cnblogs.com/jeemzz/p/11485707.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
dituo1205 发布了0 篇原创文章 · 获赞 0 · 访问量 21 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: