跳表的定义:
如上图结构zskiplistNode所示,每个节点有一个对应的层级每个层级又会指向该层的后继,span是该节点和对应后继的距离,这个层级是随机赋予的,从概率上来说,上一层节点数是下一层节点数的1/p个,这就使得跳表能够形成近似于平衡p叉搜索树的结构。
插入:
函数zslInsert:
zskiplistNode *update[ZSKIPLIST_MAXLEVEL],是被插入节点的前驱节点的记录;
unsigned long rank[ZSKIPLIST_MAXLEVEL],是被插入节点的前驱节点在整个链表的位置;
分两种情况进行讨论,
1、level > zsl->level : 当前插入节点所赋予的层级高于跳表的最高层级,则该节点是zsl->level -->level之间的第一个节点,把update[zsl->level:level]设置为header[zsl->level:level],span设置为整个跳表的长度,将被插入节点插入到update[0:level]后面,并跟新插入节点和每一层的前驱节点的span;
2、level <= zsl->level : 当前插入节点所赋予的层级小于等于跳表的最高层级,将被插入节点插入到update[0:level]后面,并跟新插入节点和每一层的前驱节点的span,虽然[level + 1,zsl->level]之间的update节点没有更新后继,但是后继中多了一个节点,因此update[level + 1,zsl->level]的span都要+1
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
unsigned long rank[ZSKIPLIST_MAXLEVEL];
int i, level;
serverAssert(!isnan(score));
x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) {
/* store rank that is crossed to reach the insert position */
rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
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