【Redis】数据结构 —— 跳跃表
跳跃表
跳跃表(skiplist
)是一种有序数据结构,它通过在每个字节中维持多个指向其它节点的指针,从而达到快速访问节点的目的。
跳跃表是在有序链表的基础上实现的。
在有序链表中,查找元素时,只能逐一查找,时间复杂度为 O(N),操作十分缓慢。为了优化,可以考虑在链表其中的元素上建索引的方式,就得到了链表。
文章图片
跳跃表在节点查询的时间复杂度平均为 O(logN),最坏情况下 O(N),还可以通过顺序性操作来批量处理节点。
在大部分情况下,跳跃表的效率可以和平衡树相媲美,并且因为跳跃表的实现比平衡树要来得更为简单,所以有不少程序都使用跳跃表来代替平衡树。
【【Redis】数据结构 —— 跳跃表】Redis 使用跳跃表作为有序集合键的底层实现之一,如果一个有序列表包含的元素数量比较多,又或者有序集合中元素的成员是比较长的字符串时,Redis 就会使用跳跃表来作为有序集合键的底层实现。
Redis 只在两个地方用到了跳跃表,一个是实现有序集合键,另一个是在集群节点中用作内部数据结构。
跳跃表的实现
跳跃表节点
typedef struct zskiplistNode {
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned int span;
} level[];
struct zskiplistNode *backward;
double score;
robj *obj;
} zskiplistNode;
level
: 包含多个元素,每个元素都包含一个指向其它节点的指针,程序可以通过这些层来加快访问其它节点的速度,一般来说,层的数量越多,访问其它节点的速度就越快;
每次创建一个新跳跃表节点的时候,程序都根据幂次定律随机生成一个介于 1 和 32 之间的值作为level
数组的大小,这个大小就是层的“高度”
forward
: 每个层都有一个指向表尾方向的前进指针,用于从表头向表尾方向访问节点。span
: 代表层的跨度,用于记录两个节点之间的距离。两个节点之间的跨度越大, 它们相距就越远;指向 null 的所有前进指针的跨度都为 0,因为它们没有连向任何节点。
backward
: 节点的后退指针用于从表尾想表头方向访问节点。跟可以一次跳过多个节点的前进指针不同,因为每个结点只有一个后退指针,所以每次只能后退至前一个节点。score
: 跳跃表的所有节点都按分值从小到大来排序。obj
: 是一个指针,指向一个字符串对象,而字符串对象则保存着一个 SDS 值。
跳跃表
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
header
: 指向跳跃表的表头指针tail
: 指向跳跃表的表尾指针length
: 记录节点的数量level
: 记录跳跃表中层数最大的节点的层数
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长