redis数据结构-跳跃表

文章目录

    • 简介
    • 查找过程
    • 插入以及更新过程

简介

跳跃表(skiplist)是一种有序数据链表结构, 它通过在每个节点中维持多个指向其他节点的指针, 从而达到快速访问节点的目的。查询平均性能为O(logN),最坏的情况会出现O(N)情况,而redis中的zset在数据较多的时候底层就是采用跳跃表去实现的,元素较少的时候会进行小对象压缩采用压缩列表实现。

小对象压缩条件:

hash-max-zipmap-entries 512 # hash 的元素个数超过 512 就必须用标准结构存储
hash-max-zipmap-value 64 # hash 的任意元素的 key/value 的长度超过 64 就必须用标准结构存储
list-max-ziplist-entries 512 # list 的元素个数超过 512 就必须用标准结构存储
list-max-ziplist-value 64 # list 的任意元素的长度超过 64 就必须用标准结构存储
zset-max-ziplist-entries 128 # zset 的元素个数超过 128 就必须用标准结构存储
zset-max-ziplist-value 64 # zset 的任意元素的长度超过 64 就必须用标准结构存储
set-max-intset-entries 512 # set 的整数元素个数超过 512 就必须用标准结构存储

redis数据结构-跳跃表_第1张图片
从上述图我们可以看出跳跃表有以下几个特点:
1.跳跃表的每个节点都有多层构成。
2.跳跃表存在一个头结点,该头结点有64层结构,每层都包含指向下个节点的指针,指向本层下个节点中间所跨越的节点个数跨度(span)。
3.除头结点以外,层高最搞的节点为该条约表的level,图中的跳跃表level为3。
4.每层都是一个有序链表。
5.最底层的有序链表包含所有的节点数,也即是整个跳跃表的长度。

跳跃表每个节点都维护了多个指向其他节点的指针,所以在进行查询、更新、删除等操作的时候不需要进行整条链表的遍历,可以通过维护的指针过滤掉中间的很多节点,从而达到很快速的访问效果,一般情况来说跳跃表的性能能与平衡树相媲美的,而且跳跃表实现较为简单,所以这也是redis为什么采用跳跃表来作为zset底层的数据结构实现。

查找过程

跳跃表的查询,跳跃表有多层的情况下查询复杂度为O(logN),如果跳跃表就一层那么查询复杂度会上升为O(N),接下来我们就用图1的实例来模拟下查询score为70的节点的具体查询过程。
redis数据结构-跳跃表_第2张图片
如图所示我们需要找到score为70的节点,查找首先从header开始,因为level为3我们先从L2开始往后开始遍历,查找到第一个节点,发现score比70小,继续往后遍历查找到第五个节点,发现score比70到,于是从当前节点往下一层进行查找,查找到节点3,以此类推,最终查询到score为70的节点。

插入以及更新过程

插入过程:
跳跃表插入节点的时候,首先需要通过score找到自己的位置,也就是需要先走一步查找过程,找到新节点所处的位置的时候就创建一个新节点,并对新节点分配一个层数(这里层数的分配redis采用的是random随机机制,分配层数从1开始,每次晋升为上一层的概率为0.25),层数分配完了之后将前后指针进行赋值将新节点与旧节点串起来,如果层数大于当前的level还需要进行level的更新操作。

更新过程:
更新过程会稍微复杂一些,更新其实就是插入,只不过插入的时候发现value已经存在了,只是需要调整一下score值,如果更新的score值不会带来位置上的改变,那么直接更新score就行不需要进行调整位置,但是如果新score会导致排序改变,那么就需要调整位置了,redis采用的方式比较直接就是先删除这个元素然后再插入这个元素即可,前后需要两次路径搜索。

参开文献:
1.Redis 深度历险:核心原理与应用实践

你可能感兴趣的:(redis)