redis - 跳跃表详细介绍

redis吸引很多人使用的一个重要的原因,就是它对众多数据类型的支持。包括string,hash,set,zset,list等五种数据对象。

其中zset用来保证数据的有序存储,实现中,redis使用跳跃表和压缩列表,作为zset的底层实现。当元素数量比较多,或者元素成员是比较长的字符串时,底层实现采用跳跃表。

跳跃表是什么?

一种有序的数据结构,通过在节点中维持多个指向其它节点的指针,达到快速访问的目的。

跳跃表的好处是什么?

1. 跟平衡树相比,实现简单;

2. 平均复杂度为O(logN),最坏为O(N);

跳跃表的数据结构由 zskiplistNode 和 zskiplist 两个结构定义,zskiplistNode表示跳跃表节点,zskiplist保存跳跃表节点的相关信息。

zskiplistNode的数据结构如下:

typedef struct zskiplistNode {

robj *obj;

double score;

struct zskiplistNode *backward;

struct zskiplistLevel {

struct zskiplistNode *forward;

unsigned int span;

} level[];

} zskiplistNode

skiplistLevel包含多个元素,每个元素包含一个指向其它节点的前进指针,通过它来加快访问其它节点。每次创建一个跳跃表节点的时候,会随机生成一个值,该值介于1和32之间,作为level数组的大小。span表示层的跨度,用来计算最终的位置,程序在遍历时,会将沿途访问过的所有层的跨度累计,得出目标节点的对应位置;

backward用于从表尾向表头访问节点;

score 所有节点都按照它进行排序;

obj 指向一个字符串对象;

zskiplist的数据结构:

typedef struct zskiplist {

struct zskiplistNode *header, *tail;

unsigned long length;

int level;

} zskiplist;

header,tail用来表示跳跃表的表头和表尾巴节点,length表示跳跃表的整体长度,level表示跳跃表的高度。

zskiplist的主要作用,是可以方便的对整个跳跃表进行处理,比如获取跳跃表的整个长度的信息。

跳跃表的层数如何生成?

在插入的过程中构造,向跳跃表中插入一个数值,相当于在表中插入一列从起始跳跃表节点S出发,向上的一段数值,需要确定两个元素:数值的位置和层数。由于所有链是递增序列的方式,所以位置主要是根据对应数值的比较对出。而层数,程序会先记录比该节点小的值的span,然后,随机生成介于1和32之间的数值,作为该节点的层数,该算法主要是基于冥次定律,越大的数出现的概率越小。假设level为2的概率为P,则level为3的概率为p*p,以此类推。

跳跃表查找的示例图:

图中,表示有三个节点,他们对应的score分别为1,2,3,其中,虚线,代表在跳跃表中,查找score为2,成员对象为02的节点,在查找过程中,经过了两个span为1的节点,所以,可以得出该节点在跳跃表中的排位为2。 BW表示后退指针,实线的,表示节点间的span,由于节点间的关系比较多,所以只画了几个。

时间: 2024-10-12 12:12:15

redis - 跳跃表详细介绍的相关文章

redis跳跃表

最近在阅读redis设计与实现,关于redis数据结构zset的一种底层实现跳跃表一直没有太理解,所以在搜了一下资料,终于搞懂了它的设计思路,记录一下. 参考链接:https://mp.weixin.qq.com/s?src=11&timestamp=1553915878&ver=1515&signature=SuSdA-Ka7Bs7CzSnNHgHFR7DkFFibGdRUui-FkuSRn2OJOkn6uvGznFMheSfoxaSHYlcgfGnBQ9imQdTAg5hiaq

Redis常用命令详细介绍

一.字符串 字符串键是Redis最基本的键值对类型,将一个单独的键和一个单独的值关联起来.通过字符串键,不仅可以存储和读取字符串,如果输入能被解释为整数和浮点数,还能执行自增或自减操作. 1.SET:设置字符串键的值 命令 SET key value [EX seconds|PX milliseconds] [NX|XX] 效果 为字符串键设置值,如果字符串键不存在,创建这个字符串键:如果已经存在,直接更新值.EX和PX选项设置键的生存时间(以秒或毫秒为单位).当生存时间消耗殆尽后,这个键就会被

ZABBIX数据库表详细介绍

zabbix数据库表结构的重要性想理解zabbix的前端代码.做深入的二次开发,甚至的调优,那就不能不了解数据库的表结构了. 我们这里采用的zabbix3.4.mysql,所以简单的说下我们mysql这边的表结构,其他环境不保证正确. mysql> show tables; +-----------------------+ | Tables_in_zabbix | +-----------------------+ | acknowledges | | actions | | alerts |

Redis研究-3.4 为何使用Redis跳跃表

好几天没把笔记整理上来了,一个是这几天在忙着一些投标以及项目论文的事情,哈哈,还有么 就是画图也是比较耗费我时间的,如果有好的画图建议或者工具,麻烦推荐一下,谢谢.废话不多说,直接进入今天的两个主题:二叉搜索树,平衡二叉树. 1.二叉搜索树(BST) 二叉搜索树的定义很简单:是二叉树,且满足两个条件:如果有左孩子,则左孩子的关键字一定不大于父节点的关键字,如果有右孩子,则右孩子的关键字不小于父节点的关键字.同时,左右子树都是二叉搜索树. BST_1 中序遍历得到的结果是:1.2.3.4.5.6.

activiti工作流数据库表详细介绍(23张表)

Activiti的后台是有数据库的支持,所有的表都以ACT_开头. 第二部分是表示表的用途的两个字母标识. 用途也和服务的API对应. ACT_RE_*: 'RE'表示repository. 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等). ACT_RU_*: 'RU'表示runtime. 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据. Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录. 这样运行时表可以一直很小速度很快.

Activiti工作流框架学习(一)之通用数据表详细介绍

文/朱季谦 Activiti工作流引擎自带了一套数据库表,这里面有一个需要注意的地方: 低于5.6.4的MySQL版本不支持时间戳或毫秒级的日期.更糟糕的是,某些版本在尝试创建此类列时将引发异常,而其他版本则不会.执行自动创建/升级时,引擎将在执行DDL时更改它.使用DDL文件方法时,既可以使用常规版本也可以使用其中带有mysql55的特殊文件(这适用于低于5.6.4的任何版本).后一个文件将具有没有毫秒精度的列类型. 笔者曾经在5.6.0版本做过试验,发现是无法自动生成23张表的,但在5.6.

dede_member|会员表详细介绍

dedecms二次开发目录点这个:dedecms二次开发教程目录 字段 类型 整理 属性 Null 默认 额外 mid mediumint(8) UNSIGNED 是 NULL 会员ID mtype enum('个人','企业') utf8_general_ci 是 个人 会员类型 userid char(20) utf8_general_ci 是 注册用户名 pwd char(32) utf8_general_ci 是 密码 uname char(36) utf8_general_ci 是 昵

dede_tagindex|Tags标签表详细介绍

dedecms二次开发目录点这个:dedecms二次开发教程目录 字段 类型 整理 属性 Null 默认 额外 id int(10) UNSIGNED 是 NULL Tagid tag char(12) utf8_general_ci 是 TAG内容 count int(10) UNSIGNED 是 0 点击 total int(10) UNSIGNED 是 0 文档数 weekcc int(10) UNSIGNED 是 0 周统计 monthcc int(10) UNSIGNED 是 0 月统

dede_sysconfig|系统参数表详细介绍

dedecms二次开发目录点这个:dedecms二次开发教程目录 字段 类型 整理 属性 Null 默认 额外 aid smallint(8) UNSIGNED 是 0 参数ID varname varchar(20) utf8_general_ci 是 参数名 info varchar(100) utf8_general_ci 是 变量说明 groupid smallint(6) 是 1 变量类型ID type varchar(10) utf8_general_ci 是 string 变量类型