这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
8redis zset类型数据结构跳跃表
什么是跳跃表?
跳跃表是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。查找节点时间复杂度为O(logN),最坏O(N)
Redis只在两个地方用到跳跃表,一是实现有序集合键,另一个是在集群节点中用作内部数据结构
跳跃表节点的实现在redis.h中定义
/* ZSETs use a specialized version of Skiplists */
/*
* 跳跃表节点
*/
typedef struct zskiplistNode {
// member 对象
robj *obj;
// 分值
double score;
// 后退指针
struct zskiplistNode *backward;
// 层
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 这个层跨越的节点数量
unsigned int span;
} level[];
} zskiplistNode;
/*
* 跳跃表
*/
typedef struct zskiplist {
// 头节点,尾节点
struct zskiplistNode *header, *tail;
// 节点数量
unsigned long length;
// 目前表内节点的最大层数
int level;
} zskiplist;
跳跃表由跳跃节点构成,跳跃表中header和tail指针分别指向跳跃表的表头和表尾节点,通过这两个指针,程序定位表头节点和表尾节点的复杂度为O(1)
length记录节点数量,获取跳跃表长度时间复杂度为O(1)
level属性表示目前表内节点的最大层数
跳跃表节点的level数组中每个元素包含一个指向其他节点的指针,程序可以通过这些层来加快访问其他节点的速度,层的数量越多,访问其他节点的速度就越快
每次创建一个新跳跃表节点的时候,程序都会根据幂次定律随机生成一个介于1和32之间的值作为level数组的大小
节点的分值是一个double类型的浮点数,跳跃表中的所有节点都按分值从小到大来排序。
节点的成员对象是一个指针,指向一个字符串对象,字符串对象保存一个SDS值
同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的**,分值相同的节点按照成员对象在字典序中的大小进行排序**
总结
跳跃表是有序集合的底层实现之一
redis跳跃表由zskiplist和在zskiplistNode构成,zskiplist保存跳跃表信息,zskiplistNode表示跳跃表节点
跳跃表节点层高在1到32之间的随机数
同一跳跃表中分值可以相同,每个节点的成员对象必须是唯一的,节点按照分值大小排序,分值相同按成员对象在字典序中的大小排序。