Redis:跳表
Jin Hu

Redis的ZSet类型底层用到了跳表,来支持平均复杂度的节点查找。

需要注意的是,Redis使用跳表时,实际用了跳表和哈希表双份保存,来分别支持高效的范围查找和单点查询(哈希表不支持有序)。

Skip List–跳表(全网最详细的跳表文章没有之一)_skip-list-CSDN博客

什么是跳表

有序链表的增删改查平均时间复杂度都是O(n),跳表则是基于链表,建立多级索引,通过多级索引检索定位将增删改查时间复杂度降为

对于一个有2级索引的三层跳表,每级索引的索引个数都是基于下层元素个数的一半。

image

查询跳表

查询是会先从最高层,沿着链表查询,如果大于目标节点,就向下移动一层,直到找到目标元素或者到底最底层。这样类似平衡树但更加直观。空间复杂度为n/2+n/4+…+2=n-2, 即O(n)。

image

更新跳表

插入数据首先会查询需要插入的位置,时间复杂度。然后需要更新索引,为了避免重建索引需要(维护n-2个索引),因此随机决定索引层级。

原理:足够随机的话,索引是均匀的,因此随机选取n/2的元素做以及索引,做k级索引。

randomLevel产生一个1-MAX_LEVEL(索引最高层数)的随机数,返回1表示不建立索引,其他数i则表示建立1-i-1级索引。

如何实现这个randomLevel函数?

产生随机数,如果不超过SKIPLIST_P(0.5),则levle+1,否则返回level,这样产生1的概率就是1/2。redis中这个SKIPLIST_P是0.25。

删除数据

删除时除了原始链表,索引中也需要删除,过程就是类似查找,查找索引过程中遇到对应的数据就删除,时间复杂度为

为什么用跳表,不用平衡树、红黑树、B+树?

主要是redis采用跳表实现zset是为了高效地进行区间查找,单个值定位其实会通过哈希表,尽管增删、以及有序性的维护用红黑树是一样的,但是按照区间查找这个操作跳表可以用O(logN)定位后遍历即可,更加高效。此外跳表实现比红黑树简单。

类似地,插入和删除来说,跳表比平衡树简单

为什么不用B+树

B+树主要是针对IO频繁场景设计的,Redis是内存数据库,不需要进行频繁IO,相对B+树来说更节省内存(索引少),维护简单。

主要是节约内存(相对B树)、有序区间操作比其他树好、更容易实现与调试

 评论