// src/t_zset.c
typedef struct zskiplistNode {
robj *obj; // 元素
double score; // 分值用于排序
struct zskiplistNode *backward; // 前驱节点
struct zskiplistLevel {
struct zskiplistNode *forward; // 后继节点
unsigned int span; // 层跨度,记录本节点到下个节点跨过了几个元素
} level[]; // 分层数组
} zskiplistNode;
// src/t_zset.c
// zadd key field score,参数里的 ele 是 field
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
for (i = zsl->level-1; i >= 0; i--) { // 从最上层开始,遍历每层
while (x->level[i].forward &&
(x->level[i].forward->score < score ||
(x->level[i].forward->score == score &&
sdscmp(x->level[i].forward->ele,ele) < 0))) // scrore相同的,比较字符串值
{
x = x->level[i].forward;
}
update[i] = x; // 使用 update 数组记录每层 x 插入位置的前驱节点
}
level = zslRandomLevel(); // 随机生成本次插入的层数,每多一层,概率*0.25
x = zslCreateNode(level,score,ele); // 新建层数=level 的 entry 节点
for (i = 0; i < level; i++) {
x->level[i].forward = update[i]->level[i].forward; // 将 x.forward 指向原下一个节点
update[i]->level[i].forward = x;
}
}
// 随机生成层数
#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^64 elements */
#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
int zslRandomLevel(void) {
int level = 1;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) // 等价于 while (random() < 0.25)
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
// new 一个跳表 node 结构
zskiplistNode *zslCreateNode(int level, double score, sds ele) {
zskiplistNode *zn =
zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
zn->score = score;
zn->ele = ele;
return zn;
}
这个值是对空间和时间的权衡。p 值太大的话,上层索引节点数量太多,上层几乎退化成顺序遍历,相当于没有索引;p 值太小,上层索引过于稀疏,起不到作用,最后也只能到最下层顺序遍历。
head 5 tail
head 1 5 9 12 tail
head 1 2 3 4 5 6 7 8 9 10 11 12 tail