1、组成结构

跳跃表结构

2、接口API

zslCreate:初始化zskipList的层数为1,长度为0,尾指针为NULL,创建zskiplistNode哨兵结点,结点层数为32,每层的前向指针为NULL,跨度为0。

zskiplist *zslCreate(void) {int j;zskiplist *zsl;zsl = zmalloc(sizeof(*zsl));zsl->level = 1;zsl->length = 0;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;
}

zslFree:从哨兵结点开始从左向右删除,最后删除zskipList

void zslFree(zskiplist *zsl) {zskiplistNode *node = zsl->header->level[0].forward, *next;zfree(zsl->header);while(node) {next = node->level[0].forward;zslFreeNode(node);node = next;}zfree(zsl);
}void zslFreeNode(zskiplistNode *node) {sdsfree(node->ele);zfree(node);
}

zslInsert:首先找到第一个大于等于score或者在分数相同时,找到第一个元素大于等于ele的结点。同时计算相应层的rank,记录下每层需要更新的位置update。根据传参数和随机选择的层数创建结点。

判断新节点层数是否大于原跳表最大节点层数,若大于则对新增层数做必要处理

将新节点插入到目标位置,即连接各前向,后向节点指针。

更新插入节点及前驱节点的 span

zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;unsigned int 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))){rank[i] += x->level[i].span;x = x->level[i].forward;}update[i] = x;}/* we assume the element is not already inside, since we allow duplicated* scores, reinserting the same element 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,ele);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;elsezsl->tail = x;zsl->length++;return x;
}

zslDelete:找到满足>=score或者>=ele的节点,同时得到每层的update。存在等于score等于ele就删除节点,删除节点时更新span.如果指定node就返回删除节点,否则释放节点

int zslDelete(zskiplist *zsl, double score, sds ele, zskiplistNode **node) {zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;int i;x = zsl->header;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))){x = x->level[i].forward;}update[i] = x;}/* We may have multiple elements with the same score, what we need* is to find the element with both the right score and object. */x = x->level[0].forward;if (x && score == x->score && sdscmp(x->ele,ele) == 0) {zslDeleteNode(zsl, x, update);if (!node)zslFreeNode(x);else*node = x;return 1;}return 0; /* not found */
}void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {int i;for (i = 0; i < zsl->level; i++) {if (update[i]->level[i].forward == x) {update[i]->level[i].span += x->level[i].span - 1;update[i]->level[i].forward = x->level[i].forward;} else {update[i]->level[i].span -= 1;}}if (x->level[0].forward) {x->level[0].forward->backward = x->backward;} else {zsl->tail = x->backward;}while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)zsl->level--;zsl->length--;
}

redis中的zset相关推荐

  1. Redis中对ZSet类型的操作命令

    写在前面的话:读书破万卷,编码如有神 -------------------------------------------------------------------- ------------ ...

  2. 用Redis中的zset实现一个限流器

    你被限流过吗 我还记得14年抢红米的时候,下面这个图是我最烦的一个图 抢了两个星期,才终于买到了我的第一台小米手机:红米1s.小米商城加入了一个排队的机制,于是我们可以感知到自己被限流了,但大部分服务 ...

  3. 使用redis中的zset进行金牌、银牌、铜牌的排序操作

    通过使用redis中的zset进行金牌.银牌.铜牌的排序操作 简介: 1. Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员. 2.不同的是每个元素都会关联一个doub ...

  4. zset获取指定score_7、Redis中对ZSet类型的操作命令

    写在前面的话:读书破万卷,编码如有神 -------------------------------------------------------------------- ------------ ...

  5. Redis中的zset 存储结构(实现)原理

    同时满足以下条件时使用ziplist 编码: 元素数量小于128 个 所有member 的长度都小于64 字节 在ziplist 的内部,按照score 排序递增来存储.插入的时候要移动之后的数据. ...

  6. Redis中的zset原理以及用Java实现跳跃表

    准备工作 先在Redis官网下载最新的稳定版本6.2.按照官网给出的安装指南到Linux服务器上安装. zadd调用过程 redis/src/server.c 文件中定义了所有命令运行要调用的方法.z ...

  7. Redis中的zset 有序集合

    存储类型 sorted set,有序的set,每个元素有个score. score 相同时,按照key 的ASCII 码排序. 数据结构对比: 数据结构 是否允许重复元素 是否有序 有序实现方式 列表 ...

  8. redis中zset底层实现原理

    https://www.cnblogs.com/yuanfang0903/p/12165394.html 阅读目录 一.Zset编码的选择 二.ziplist 三.skiplist 四.skiplis ...

  9. 记录一次使用Redis中ZSet和List分页

    使用Redis的ZSet和List进行分页,两者都可以实现,共同特性相当于截取集合中的一部分,ZSet拥有去重特性,List可能会出现数据重复情况,推荐使用ZSet. 另外说明:使用其他类型就不可以, ...

最新文章

  1. 14.相同的树另一棵树的子树检查子树二叉树中的列表(教你们使用相同的套路快速解决这四道题)
  2. python framework jdon_一天学会Python Web框架(十二)产品管理
  3. 第一章 TensorFlow基础——python语法(一)
  4. php7.3安装yaf扩展
  5. 在网页中插入百度地图(实例)
  6. Java中的多重继承与组合vs继承
  7. 循环删除List集合的错误
  8. 一幅漫画趣味解读 Linux 内核
  9. ScheduledExecutorService 延迟 / 周期执行线程池
  10. ofd文件怎么打开?怎么转换成pdf格式发票?ofd文件打开教程
  11. 中国各行各业的祖师爷是谁?
  12. 计算机安装win10配置,安装Win10系统配置的最低要求
  13. python多行写入文件_写入文件
  14. 243.STAMP图形界面微生物组分析软件
  15. Ubuntu20.04开启night夜间模式保护视力
  16. 这是你了解的P2P 么?
  17. xy苹果助手未受信任_苹果ios企业签名后App无法安装?如何解决?
  18. Js同步加载图片资源
  19. java综合知识点总结基础篇
  20. IMAX重开369家中国影院;康希诺辉瑞签署疫苗推广服务协议 | 美通企业日报

热门文章

  1. 【SAP业务模式】之ICS(五):定价配置
  2. zabbix 彻底解决图片中文乱码
  3. ECshop--搜索模块细究
  4. jmeter中文_JMeter安装配置
  5. python语言的整数类型是什么-Python|你必须知道的基本数据类型之一:Number类型...
  6. 老师学python可以干嘛-你都用 Python 来做什么?
  7. 编程中python怎么读-编程语言如何在Python中读写文件
  8. 想学python有什么用-我们为什么要选择学习python?学习python有什么用?
  9. python制作工资计算器-Python制作个税计算器
  10. python找工作难吗-Python虽然很火,为啥找工作这么难?