在 Redis 中,跳跃表(Skiplist)主要用于实现有序集合(Sorted Set)数据结构。有序集合在 Redis 中的命令前缀为 Z
,例如 ZRANGE
、ZADD
、ZREM
等。有序集合中的元素是按分数(score)排序的,而跳跃表是一种高效的数据结构,可以支持快速的插入、删除和按分数排序的查找操作。
跳跃表的用途
跳跃表是一种概率平衡的数据结构,提供了类似于平衡树的时间复杂度。它被用来实现 Redis 中的有序集合,主要用于以下场景:
- 有序数据的快速查找:跳跃表允许快速按分数查找元素。例如,获取某个分数范围内的所有元素或查找某个分数对应的元素。
- 范围查询:跳跃表支持高效的范围查询,可以快速获取分数在某个范围内的所有元素。
- 排序操作:跳跃表保持元素按分数排序,支持按分数的升序或降序遍历。
主要实现文件
在 Redis 源代码中,跳跃表的实现主要集中在 zskiplist.c
文件中。该文件定义了跳跃表的数据结构及其相关操作。
跳跃表的数据结构
typedef struct zskiplistNode {
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned long span;
} level[];
struct zskiplistNode *backward;
double score;
robj *obj;
} zskiplistNode;
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
主要操作
-
插入操作:向跳跃表中插入一个元素,同时按照分数(score)排序。
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj);
-
删除操作:从跳跃表中删除一个元素。
int zslDelete(zskiplist *zsl, double score, robj *obj);
-
范围查找:查找分数在某个范围内的元素。
unsigned long zslGetRank(zskiplist *zsl, double score, robj *o); zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank);
-
范围删除:删除分数在某个范围内的所有元素。
unsigned long zslDeleteRangeByScore(zskiplist *zsl, zrangespec *range); unsigned long zslDeleteRangeByRank(zskiplist *zsl, unsigned int start, unsigned int end);
应用示例
假设有一个有序集合存储了学生的成绩,使用跳跃表可以实现以下操作:
- 插入学生成绩:
ZADD students 95 "Alice"
将 Alice 的成绩 95 插入到有序集合students
中。 - 获取某个分数范围内的学生:
ZRANGE students 0 100 WITHSCORES
获取成绩在 0 到 100 之间的所有学生及其成绩。 - 删除某个学生的成绩:
ZREM students "Alice"
从有序集合中删除 Alice 的成绩。
通过使用跳跃表,Redis 实现了高效的有序集合操作,提供了灵活而强大的数据查询和操作能力。