1、跳跃表是什么?
- 跳跃表/skiplist是一种有序数据结构,通过在每个节点上维持多个指向其它节点的指针,达到快速访问节点的目的。节点查找平均复杂度O(logN),最坏情况是O(N),还可以通过顺序性操作来批量处理节点。效率可以和平衡树媲美,在Redis中被应用。
- 在Redis中使用跳跃表作为有序集合键的底层实现之一:1)有序集合见包含的元素数量较多时 2)有序集合键的元素的成员是比较长的字符串时。
- Redis只在两个地方用到跳跃表:1)实现有序集合键 2)在集群节点中用作内部数据结构。
2、有序集合键是什么?
- 有序集合键是Redis的五种键值 之一,包括成员和分值两部分:比如水apple是成员,apple_price是对应的分值。
- 有序集合键的所有数据都保存在一个跳跃表里面,跳跃表包含多个跳跃表节点
3、如何实现一个跳跃表
跳跃表 = zskiplist{zskiplistNode},Redis的跳跃表如第一节所示,由zskiplistNode=跳跃表节点和zskiplis=保存跳跃表节点的相关信息(节点的数量、指向节点头和尾的指针等)组成。
1)跳跃表节点
typedef struct zskiplistNode {
structz zskiplistNode *backward;//后退指针
double score;//分值
robj *obj;//成员对象
struct zskiplistLevel{//层
struct zskiplistNode *forward;//前进指针
unsigned int spanl//跨度
}lever[];//数组结构
}zskiplistNode;
- 后退指针:用于从表尾到表头方向访问节点
- 分值:是一个double类型的浮点数,跳跃表中的所有与节点的分值从小到大正序排序,各个节点的成员对象不一定唯一
- 成员变量:是一个指针,指向一个字符串对象(保存着一个SDS值),各个节点的成员对象唯一
- 层:level数组可以保存多个元素,每个元素都有一个指向其他节点的指针,通过这些层来快速访问其他节点。层数越多,访问速度越快。
–每创建一个新的跳跃表节点,程序根据幂次定律随机生成一个解与1-32之间的值作为level数组的大小=层的高度
–前进指针:指向表尾巴,用于从表头到表尾访问节点
–跨度:level[i].span属性,用于记录两个节点之间的距离
2)跳跃表
//zskiplist的结构
typedef struct zskiplist{
structz zskiplistNode *header,*tail;//表头节点和表尾节点
unsigned long length;//表中节点的数量
int level;//表中层数最大的节点的层数
}zskiplist;
- header和tail是表头节点和表尾节点,通过这两个指针快速定位表头节点和表尾节点,复杂度O(1)
- length记录表中节点的数量,能快速返回跳跃表的长度,复杂度O(1)
- leverl属性能快速获取跳跃表中层数最大的节点的层数,头节点不算,复杂度O(1)
该示例表示,跳跃表中层数最大的节点的层数为5,跳跃表长度为3.