Redis使用跳跃表作为有序集合键的底层实现之一,同时Redis是在集群节点内用作内部数据结构。
跳跃表的实现
Redis的跳跃表由redis.h/zskiplistNode和redis.h/zskiplist
两个结构定义,其中zskiplistNode结构⽤于表⽰跳跃表节点,⽽zskiplist结构则⽤于保存跳跃表节点的相关信息,⽐如节点的数量,以及指向表头节点和表尾节点的指针等等。
skiplist
对于zskiplist结构:
- header指向表头节点,tail指向表尾节点
- level表示当前跳跃表中,层数最大
的那个节点的层数。(表头节点不算,层数指图中L的个数) - length记录跳跃表长度,不计表头节点。
typedef struct zskiplist {
//表头节点和表尾节点
structz skiplistNode *header, *tail;
//表中节点的数量
unsigned long length;
//表中层数最⼤的节点的层数
int level;
} zskiplist;
zskiplistNode
对于zskiplistNode结构:
- level []:构成节点的各个层,每个层定义有两个属性:forward和span,代表前进指针和跨度,上图中箭头上的数字就是跨度,代表从这个层到另一个节点的层跨过的节点数。当程序从表头节点向后遍历时,会通过该指针访问下一个节点。
- 每次创建⼀个新跳跃表节点的时候,程序都根据幂次定律(powerlaw,越⼤的数出现的概率越⼩)随机⽣成⼀个介于1和32之间的值作为level数组的⼤⼩,这个⼤⼩就是层的“⾼度”。
- 一般来说,层越多,访问其他节点的速度越快。
- level[x].forward
- level[x].span
- 跨度,用于记录两节点之间的距离,跨度是⽤来计算排位(rank)的:在查找某个节点的过程中,将沿途访问过的所有层的跨度累计起来,得到的结果就是⽬标节点在跳跃表中的排位。
- backward:后退指针。上图中BW即为后退指针,指向前一个节点。
- 与前进指针一次性跳过多个节点不同,后退指针只能挨个后退,直到null结束。
- score:分值。是一个double浮点数,上图中1.0、2.0、3.0是当前节点保存的分值,节点在跳跃表中以该分值按序排列。
- obj:成员对象指针。各个节点保存的内容,上图中o1,o2,o3即为对象。
- 指向字符串对象,字符串对象保存一个SDS值。
- 在同一个跳跃表中,各节点保存的成员对象一定不相同,但分值可以相同,各节点按分值从小到大排列,分值相同的按成员对象在字典序中的大小排列。
typedef struct zskiplistNode {
struct zskiplistNode *backward; // 后退指针
double score; // 分度值
robj *obj; // 成员对象
struct zskiplistLevel {
struct zskiplistNode *forward; // 前进指针
unsigned int span; // 跨度
} level []; // 层
} zskiplist;
标签:level,redis,zskiplistNode,表头,跳跃,节点,指针
From: https://www.cnblogs.com/wz-NO1/p/17234301.html