Redis跳表

简介: Redis跳表


简介

Redis 中的有序集合(Sorted Set)是用跳表(Skip list)来实现的。这里就需要了解一下跳表的概念。

链表:链表插入,删除某一个节点的时间复杂度是O(1),但是查询的时间复杂度是O(n)。

跳表就是解决链表在有序节点场景下的查询时间复杂度高问题。时间复杂度能达到O(logn)。

跳表

跳表是有多个层级的链表组成。如下图的多级索引和原始链表,每层索引都是一条链表。

跳表每一层的链表都会随机包含一些原始链表的节点(通过跳表的动态更新策略实现)。层数越高,链表节点越少。

查询策略

因此查询节点时,从最高层级向下查找,通过高层级索引节点的大小和待查找值大小比较,就能比较出查找值大小是在哪两个节点之间,或者就等于某个节点。再一步一步往低层级索引的链表上查找,最终总能找到相等的那个节点。

可以看出,跳表其实是一种空间换时间的策略来减少查询的时间复杂度。

动态更新策略

插入节点

  1. 在跳表中插入新元素时,需要先在底层链表中插入该元素,然后决定该元素是否要成为索引节点。
  2. 可以使用随机函数来决定该元素是否需要成为下一层的索引节点,如果需要,则在下一层都插入一个新的索引节点,该索引节点指向上一层中同一位置的元素。

删除节点

  1. 在跳表中删除元素时,需要先在底层链表中删除该元素,然后考虑是否需要删除对应的索引节点。
  2. 可以从顶层开始遍历跳表,如果某个索引节点指向的元素已经不存在了,则需要删除该索引节点,同时将上一层中相同位置的索引节点指向下一层中相同位置的元素。
  3. 如果最上层的索引节点被删除了,则需要将跳表的高度减少一层。

跳表的高度控制策略

跳表的高度控制策略通常是基于概率的可以定义一个概率p,每次插入元素时,以概率p(0<p<1)决定是否将该元素作为索引节点。查询时间复杂度就是log1/p(n)。

如果是以1/2概率决定是否添加链表,则跳表的高度最大为log2(n)。查询效率也就是log2(n)。

概率过大 vs 概率过小

概率过大,过小都不好。

概率过大会导致跳表中索引节点的数量增加,从而增加了查询时需要访问的节点数,降低了查询效率。因为跳表的查询效率取决于索引节点的数量,节点数量越多,查询效率就越低。

概率越小并不一定就越好。因为概率越小,索引节点的数量就会减少,从而节省了空间,但是查询效率也会降低。如果概率过小,跳表的高度可能无法达到预期的水平,从而失去了跳表的优势。

目录
相关文章
|
NoSQL 算法 分布式数据库
【Redis】求求你,别再问跳表了
【Redis】求求你,别再问跳表了
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
NoSQL 算法 Redis
redis7.0源码阅读(五):跳表(skiplist)
redis7.0源码阅读(五):跳表(skiplist)
1491 1
|
NoSQL Go API
Golang实现redis系列-(4)实现跳表容器
Golang实现redis系列-(4)实现跳表容器
156 0
|
存储 NoSQL Redis
Redis数据结构之——跳表skiplist
Redis数据结构之——跳表skiplist
|
存储 NoSQL Redis
零基础手把手带你阅读Redis源代码系列-ZSet底层原理详解(跳表SkipList)
>之前就说了要来西索Redis,现在来辣! >本文的部分内容参考自《小林Coding》,部分地方根据源代码进行剖析。 >Redis源码地址:https://github.com/redis/redis.git
657 0
零基础手把手带你阅读Redis源代码系列-ZSet底层原理详解(跳表SkipList)
|
存储 NoSQL Redis
Redis 跳表skiplist
Redis 跳表skiplist
|
存储 NoSQL 算法
redis6.0源码分析:跳表skiplist
redis6.0源码分析:跳表skiplist
297 0
|
NoSQL Redis 索引
Redis zset 底层数据结构之跳表
0、zset数据结构 1、zset底层的数据结构 2、跳表介绍 3、跳表增删查的时间复杂度 4、什么时候使用压缩链表,什么时候使用跳表 5、跳表的内部实现及原理 6、为什么用跳表而不用红黑树或二叉树呢.........
745 0
Redis zset 底层数据结构之跳表