【Redis】求求你,别再问跳表了

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis】求求你,别再问跳表了

跳表

使用场景

跳表(Skiplist )是一个特殊的链表,相比一般的链表,有更高的查找效率,可比拟二叉查找树

平均期望的查找、插入、删除时间复杂度都是O(log n),许多知名的开源软件(库)中的数据

结构均采用了跳表这种数据结构∶

  • Redis中的有序集合zset
  • LevelDB、RocksDB、HBase中Memtable
  • Apache Lucene中的Term Dictionary、Posting List

结构描述

我们拿我们以前的有序链表相比:

我们可以很清楚的看出,有序链表的查询比较慢,时间复杂度为O(n),它的删除和插入操作比较快,我们怎样才能让它的查询的时间复杂度也变快呢?

能不能将我们的链表实现二分的查找,也就是longN,答案是肯定的,也就是我们下面所说的这种跳表。

查询算法

跳表的查询和我之前做过的一道题特别类似,二维数组的查找

假设我们查询31这个数字

  • 我们的header开始,依次进行查询,
  • 31不在负无穷到17,往右边,到达17,继续比较,在17到正无穷之间,往下跑

整个查询过程如下所示

插入算法

对于插入来说,我们比如要插入一个21的数值

  • 类似查询算法,到达17这个点,进一步到达20这个点,然后在20的后面进行插入
  • 插入完了以后,这时候要考虑索引的问题,也就是我们需要将当前这个数值向上几层呢
  • 通过一个50%的概率决定,也就是绝大多数文章讲的抛硬币(_

删除算法

对于删除来说,我们比如要插入一个17的数值

  • 先进行查询操作,找到这个数字
  • 将其及索引进行删除

时间复杂度

我们知道单链表查询的时间复杂度为O(n),而插入、删除操作需要先找到对应的位置,所以插入、删除的时间复杂度也是O(n)。

那么,跳表的时间复杂度是多少呢?

如果按照标准的跳表来看的话,每一级索引减少k/2个元素(k为其下面一级索引的个数),那么整个跳表的高度就是(log n)。

学习过平衡二叉树的同学都知道,它的时间复杂度与树的高度成正比,即O(log n)。

所以,这里跳表的时间复杂度也是O(log n)。(这里不一步步推倒了,只要记住,查询时每次减少一半的元素的时间复杂度都是O(log n),比如二叉树的查找、二分法查找、归并排序、快速排序)

空间复杂度

我们还是以标准的跳表来分析,每两个元素向上提取一个元素,那么,最后额外需要的空间就是:

n/2 + (n/2)^2 + (n/2)^3 + … + 8 + 4 + 2 = n - 2

所以,跳表的空间复杂度是O(n)。

总结

  • 跳表是可以实现二分查找的有序链表
  • 每个元素插入时随机生成它的索引的高度
  • 最低层包含所有的元素
  • 如果一个元素出现在level(x),那么它肯定出现在x以下的level中
  • 每个索引节点包含两个指针,一个向下,一个向右
  • 跳表查询、插入、删除的时间复杂度为O(log n),与平衡二叉树接近

Redis使用跳表而不是红黑树?

  • 插入元素
  • 删除元素
  • 查找元素
  • 有序输出所有元素
  • 查找区间内所有元素

前四项红黑树都可以完成,且时间复杂度与跳表一致

但是,最后一项,红黑树就不如跳表查询的快

在跳表中,要查找区间的元素,我们只要定位到两个区间端点在最低层级的位置,然后按顺序遍历元素就可以了,非常高效。

而红黑树只能定位到端点后,再从首位置开始每次都要查找后继节点,相对来说是比较耗时的。

跳表实现起来很容易且易读,红黑树实现起来相对困难,所以Redis选择使用跳表来实现有序集合。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
7月前
|
NoSQL 算法 Redis
redis7.0源码阅读(五):跳表(skiplist)
redis7.0源码阅读(五):跳表(skiplist)
318 1
|
7月前
|
NoSQL Redis C++
Redis跳表
Redis跳表
67 0
|
7月前
|
NoSQL Go API
Golang实现redis系列-(4)实现跳表容器
Golang实现redis系列-(4)实现跳表容器
44 0
|
7月前
|
存储 NoSQL Redis
Redis数据结构之——跳表skiplist
Redis数据结构之——跳表skiplist
|
存储 NoSQL Redis
Redis从入门到精通之底层数据结构跳表 SkipList
跳表(Skip List)是一种基于链表的数据结构,用于快速地插入、删除和查找元素。跳表通过多层级的指针数组来实现快速的操作,时间复杂度为O(log n),其中n为跳表中元素的个数。Redis中的有序集合(Sorted Set)就是通过跳表来实现的。
846 14
Redis从入门到精通之底层数据结构跳表 SkipList
|
存储 NoSQL Redis
Redis 跳表skiplist
Redis 跳表skiplist
|
存储 NoSQL 算法
redis6.0源码分析:跳表skiplist
redis6.0源码分析:跳表skiplist
63 0
|
存储 NoSQL Redis
零基础手把手带你阅读Redis源代码系列-ZSet底层原理详解(跳表SkipList)
>之前就说了要来西索Redis,现在来辣! >本文的部分内容参考自《小林Coding》,部分地方根据源代码进行剖析。 >Redis源码地址:https://github.com/redis/redis.git
152 0
零基础手把手带你阅读Redis源代码系列-ZSet底层原理详解(跳表SkipList)
|
存储 NoSQL 安全
Redis源码之跳表数据结构
Redis源码之跳表数据结构