[redis设计与实现][4]基本数据结构——跳跃表

Redis使用跳跃表和字典共同来实现有序集合键(sorted set)。

定义:
跳跃表节点:
[cce lang="c"]
typedef struct zskiplistNode {
//成员对象
robj *obj;
//分值
double score;
//后退指针
struct zskiplistNode *backward;
//层结构
struct zskiplistLevel {
//前进指针
struct zskiplistNode *forward;
//跨度
unsigned int span;
} level[];
} zskiplistNode;
[/cce]
跳跃表定义:
[cce lang="c"]
typedef struct zskiplist {
//跳跃表头、尾指针
struct zskiplistNode *header, *tail;
//跳跃表长度
unsigned long length;
//跳跃表层数
int level;
} zskiplist;
[/cce]

zskiplist *zslCreate(void);
[cce lang="c"]
zskiplist *zslCreate(void) {
int j;
zskiplist *zsl;

zsl = zmalloc(sizeof(*zsl));
zsl->level = 1;
zsl->length = 0;
//创建头节点,头节点永远有最高层
//#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
//初始化头节点的每一层
for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) { zsl->header->level[j].forward = NULL;
zsl->header->level[j].span = 0;
}
zsl->header->backward = NULL;
zsl->tail = NULL;
return zsl;
}
zskiplistNode *zslCreateNode(int level, double score, robj *obj) {
zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
zn->score = score;
zn->obj = obj;
return zn;
}
[/cce]
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj);
[cce lang="c"]
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
unsigned int rank[ZSKIPLIST_MAXLEVEL];
int i, level;

redisAssert(!isnan(score));
x = zsl->header;
//遍历查找当前score对应的插入位置
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 &&
compareStringObjects(x->level[i].forward->obj,obj) < 0))) { //累加跨度 rank[i] += x->level[i].span;
x = x->level[i].forward;
}
//当前层要更新的节点
update[i] = x;
}
/* we assume the key is not already inside, since we allow duplicated
* scores, and the re-insertion of score and redis object should never
* happen since the caller of zslInsert() should test in the hash table
* if the element is already inside or not. */
//随机一个当前节点的层数
level = zslRandomLevel();
//如果是最高层,需要修正
//在以前最高层以上的,跨度都修复为跳跃表原长度,前置节点都改为头结点
if (level > zsl->level) {
for (i = zsl->level; i < level; i++) { rank[i] = 0; update[i] = zsl->header;
update[i]->level[i].span = zsl->length;
}
//跳跃表的总层数改成最新的层数
zsl->level = level;
}
x = zslCreateNode(level,score,obj);
//每一层的链表构建
for (i = 0; i < level; i++) { x->level[i].forward = update[i]->level[i].forward;
update[i]->level[i].forward = x;

/* update span covered by update[i] as x is inserted here */
//当前节点每层跨度计算
x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
//当前节点每层插入节点跨度修改
update[i]->level[i].span = (rank[0] - rank[i]) + 1;
}

/* increment span for untouched levels */
for (i = level; i < zsl->level; i++) {
update[i]->level[i].span++;
}

//修改当前节点的前置节点等
x->backward = (update[0] == zsl->header) ? NULL : update[0];
if (x->level[0].forward)
x->level[0].forward->backward = x;
else
zsl->tail = x;
zsl->length++;
return x;
}
int zslRandomLevel(void) {
int level = 1;
//#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) level += 1; return (level

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据