[redis设计与实现][4]基本数据结构——跳跃表-阿里云开发者社区

开发者社区> 会影> 正文

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

简介: Redis使用跳跃表和字典共同来实现有序集合键(sorted set)。 定义: 跳跃表节点: [cce lang=”c”] typedef struct zskiplistNode { //成员对象 robj *obj; //分值 double score; //后退指针 st
+关注继续查看

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 }
[/cce])>


)>

转载自:https://coolex.info/blog/450.html)>

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
[redis设计与实现][10]sentinel——简介和启动
Sentinel(Redis 3.0.0-rc1) Sentinel是Redis HA方案,一个或多个Sentinel实例组成的Sentinel系统,可以监视任意多个主服务器(master), 以及这些主服务器属下的所有从服务器(slave),并在被监视的主服务器进入下线状态时,自动在将被下线主
1235 0
[20180312]不好的数据结构设计3.txt
[20180312]不好的数据结构设计3.txt --//上个星期提到一种不好的数据结构设计.今天在提到一种: --//就是本来一行保存的信息,变成竖着保存,涉及一些安全信息,通过例子来说明: 1.
723 0
LintCode 题解丨面试真题:两数之和 III-数据结构设计
LintCode 题解丨面试真题:两数之和 III-数据结构设计
160 0
redis数据结构、持久化、缓存淘汰策略
redis数据结构、持久化、缓存淘汰策略Redis 单线程高性能,它所有的数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
928 0
redis数据结构实现--压缩列表(ziplist)
redis数据结构实现(六) 压缩列表(ziplist)是链表键和哈希键的底层实现之一。当链表键或哈希键只有少量列表项,且列表项中是小整数值或短字符串,则会采用压缩列表作为底层实现。 6.1 压缩列表的实现 压缩列表是为了节约内存而开发的,由一系列特殊编码的连续内存块组成的顺序型数据结构。
2048 0
[redis设计与实现][8]数据库
Redis数据库定义: typedef struct redisDb { dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of k
1624 0
带你读《Java程序设计与计算思维》之二:认识数据处理与表达式
程序设计的过程就是一种计算思维的表现,《Java程序设计与计算思维》结合Java程序设计语言的教学特点,遵循计算思维的方式,图解重要概念,通过大量的范例程序讲解和上机编程实践来指导读者活用Java程序语法,兼顾培养计算思维和学习面向对象程序设计的双目标。
497 0
+关注
59
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载