Redis Skiplist
Based on Redis 7.0.11.
Skiplist 定义
typedef struct zskiplistNode {
sds ele;
double score;
struct zskiplistNode *backward;
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned long span;
} level[];
} zskiplistNode;
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;zskiplistNode.score:节点的权重,它决定了节点在列表中的位置(从小到大);分值相同的节点则按照ele的字典顺序排序。zskiplistNode.level:level 数组包含指向后续节点的指针,nodes[a].level[N]指向nodes[b].level[N]或 NULL, 其中a < b。新节点会随机创建一个介于[1, 32]大小的 level 数组。zskiplistNode.zskiplistLevel.span:步长或跨度,nodes[a].level[N]指向nodes[b].level[N]跨越的节点数(包含结尾)。
示意图:
+--+
|L32 --0-> NULL
+--+
....
+--+ +--+
|L5| -------------3------------> |L5| --0-> NULL
+--+ +--+ +--+
|L4| --1-> |L4| -------2-------> |L4| --0-> NULL
+--+ +--+ +--+
|L3| --1-> |L3| -------2-------> |L3| --0-> NULL
+--+ +--+ +--+ +--+
|L2| --1-> |L2| --1-> |L2| --1-> |L2| --0-> NULL
+--+ +--+ +--+ +--+
|L1| --1-> |L1| --1-> |L1| --1-> |L1| --0-> NULL
+--+ +--+ +--+ +--+
+--- |BW| <---- |BW| <---- |BW|
| +--+ +--+ +--+
NULL |1.| |2.| |3.|
+--+ +--+ +--+
|o1| |o2| |o3|
+--+ +--+ +--+
head tail换个角度,跳表非常像某一链接及其子序列链表的加总。
搜索节点
从 head 最高层开始,往下逐层缩小查找范围,有点类似二分查找。
插入新节点
- 找到新节点将要插入的位置。
- 找到新节点在每层链表中的前驱节点,即往前距新节点最近的
level[N]。例如o2.L1、o2.L2和o1.L4。 - 修改前驱节点的
level[L].forward及span。 - 对于位于新节点之前且
nodes[N].level[L] && L > new.level.length的节点,span++。例如o1.L4和head.L5。 - 更新
backward指针。例如o3.BW。
+--+
|L32 --0-> NULL
+--+
....
+--+ +--+
{L5} ------------------4------------------> |L5| --0-> NULL
+--+ +--+ +--+
|L4| --1-> {L4} -------------3------------> |L4| --0-> NULL
+--+ +--+ +--+ +--+
|L3| --1-> {L3} -------2-------> |L3| --1-> |L3| --0-> NULL
+--+ +--+ +--+ +--+ +--+
|L2| --1-> |L2| --1-> {L2} --1-> |L2| --1-> |L2| --0-> NULL
+--+ +--+ +--+ +--+ +--+
|L1| --1-> |L1| --1-> {L1} --1-> |L1| --1-> |L1| --0-> NULL
+--+ +--+ +--+ +--+ +--+
+--- |BW| <---- |BW| <---- |BW| <---- {BW}
| +--+ +--+ +--+ +--+
NULL |1.| |2.| |2.| |3.|
+--+ +--+ +--+ +--+
|o1| |o2| |on| |o3|
+--+ +--+ +--+ +--+
head new tailKey takeaways
节点的 ele 字段类型为 Redis SDS。