前言
跳跃表是一种以O(log N)期望时间支持查找、插入、删除操作的、有序的数据结构。
Redis使用跳跃表作为有序集合键的底层实现之一。
跳表的基本实现原理参考:《Skip lists: a probabilistic alternative to balanced trees》
Redis中的跳表实现
Redis的跳表由zskiplistNode, zskiplist两个数据结构定义。
跳跃表节点的实现如下,由redis.h/zskiplistNode
定义:
1 | /* ZSETs use a specialized version of Skiplists */ |
Redis中跳表和普通跳表区别如下:
- 添加span属性,表示跨度,用于计算排位。
- 添加backward后退指针,用于表尾到表头访问节点,每次只能后退一个节点。
- ele表示SDS对象,必须是唯一的,而普通跳表存储的值可以不唯一。
- 添加score属性,表示分值,这是Redis跳表排序的依据,score的值允许重复。如score值相同,按ele字典序排列
Redis通过zskiplist结构来持有跳表:
1 | typedef struct zskiplist { |
跳表API
API | 功能 | 复杂度 |
---|---|---|
zskiplist *zslCreate(void); | 创建跳表 | O(1) |
void zslFree(zskiplist *zsl); | 释放跳表 | O(1) |
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele); | 插入 | O(logN) |
int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node); | 删除跳表 | O(logN) |
unsigned long zslGetRank(zskiplist *zsl, double score, sds ele); | 返回给定节点的排位 | O(logN) |
zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank); | 返回指定排位的节点 | O(logN) |
参考资料
《Redis设计与实现》第5章 跳跃表