跳跃表(skiplist)是一种有序数据结构,它经过在每一个节点中维持多个指向其余节点的指针,从而达到快速访问节点的目的。redis
跳跃表支持平均O(logN),最坏O(N)复杂度的节点查找,还能够经过顺序性操做批量处理节点。
在大部分状况下,跳跃表的效率能够和平衡树相媲美,而且由于跳跃表的实现比平衡数要来得更为简单,因此有很多程序都使用跳跃表来代替平衡树。
redis 使用跳跃表做为有序集合键的底层实现之一,若是一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员(member)是比较长的字符串时,Redis就会使用跳跃表做为有序集合键的底层实现。数据结构
和链表,字典等数据结构被普遍地应用在Redis内部不一样,Redis只有两个地方用到了跳跃表,一个是实现有序集合键,另外一个是在集群节点中用做内部数据结构,除此以外,跳跃表在Redis里面没有其余用途。spa
/* ZSETs use a specialized version of Skiplists */ typedef struct zskiplistNode { robj *obj; //成员对象 double score; //分值 struct zskiplistNode *backward; //后退指针 struct zskiplistLevel { //层 struct zskiplistNode *forward; //前进指针 unsigned int span; //跨度 } level[]; } zskiplistNode; typedef struct zskiplist { struct zskiplistNode *header, *tail; //header:指向跳跃表的表头节点,tail :指向跳跃表的表尾节点 unsigned long length; //记录跳跃表的长度,也便是,跳跃表目前包含节点的数量(表头节点不计算在内) int level; //记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内) } zskiplist; typedef struct zset { dict *dict; zskiplist *zsl; } zset;
hearder和tail 指针分别指向跳跃表的表头和表尾节点,经过这两个指针,程序定位表头节点和表尾节点的复杂度为O(1)。指针
经过使用length属性来记录节点的数量,程序能够在O(1)复杂度内返回跳跃表的长度。code
总结:对象
跳跃表是有序集合的底层实现之一。排序
Redis的跳跃表实现由zskiplist 和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(好比表头节点,表尾节点,长度),而zskiplistNode 则用于表示跳跃表节点。ip
每一个跳跃表节点的层高都是1至32之间的随机数。ci
在同一个跳跃表中,多个节点能够包含相同的分值,但每一个节点的成员对象必须是惟一的。字符串
跳跃表中的节点按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序。