跳跃表(Skip List)是一种用于有序元素序列快速搜索的数据结构。它的效率和红黑树以及AVL(自平衡二叉查找树)相近,可是实现起来更加容易(相对于复杂的自平衡算法)。redis
大概结构以下:算法
在最原始的已排序的链表基础上经过添加多个层级,理想状况下每一个层级节点数是上一个层级1/2,查找时经过最上层开始,利用须要查找的值与当前层级值对比缩小范围并经过下一层进一步缩小范围,最终找到查询值的方式(相似于二分查找方式)。数组
Redis使用跳跃表做为有序集合的底层实现之一,若是一个有序集合包含的元素比较多或者集合中的元素时比较长的字符串时,Redis会使用跳跃表做为有序集合键的底层实现。数据结构
Redis跳跃表大体结构以下:spa
分为zskiplistNode和zskiplist两个结构,代码以下:指针
redis.h/zskiplistNode:code
typedef struct zskiplistNode { // 成员对象 robj *obj; // 分值 double score; // 后退指针 struct zskiplistNode *backward; // 层 struct zskiplistLevel { // 前进指针 struct zskiplistNode *forward; // 跨度 unsigned int span; } level[]; } zskiplistNode;
level数组包含了当前元素在不用层高的下一个元素指针和跨度,Redis中程序会根据幂次定律(power law, 越大的数出现的几率越小)随机生成一个介于1~32之间的值做为level数组的大小,这个大小就是层的“高度”。对象
span表示跨度,因为底层的链表是有序的,因此从头部到当前节点跨度之和也就是元素的排位。用于Redis有序集合的ZRANK命令获取元素排行。排序
backward回退指针用于逆序遍历链表,对应Redis有序集合的ZREVRANGE命令。ip
redis.h/zskiplist:
typedef struct zskiplist { // 表头节点和表尾节点 struct zskiplistNode *header, *tail; // 表中节点的数量 unsigned long length; // 表中层数最大的节点的层数 int level; } zskiplist;