跳表
要先有跳表的数据结构基础:
跳表是链表的一个变种,通过增加多余的指针,将单向链表变成多向链表,进而使跳表的查询效率和平衡二叉树看齐(平均o(logN),最坏o(N)),而且较之二叉树实现方便。
而跳表本身,有一些比较迷的实现策略:比如,新增节点的层次是通过随机数(抛硬币)指定的,存在一个随机概率,这在redis内,概率为1/4,同时规定,层数最大为32
结构:
/**
* 跳表节点
**/
typedef struct zskiplistNode{
struct zskiplistLevel{
zskiplistNode *forward;//当前层(level)指向下一节点的指针
unsigned int span;//到下一个节点之间的距离
} level[];
struct zskiplistNode *backward;//指向前一个节点的指针
double score;
robj * obj;//存储的redis对象
}
要点:
- redis内的跳表存在一个zskiplist的结构体,内部保存一个跳表的头、尾、节点个数和当前层数
- redis的跳表,第一个节点是不保存数据的,而只起到连接各个层的作用
- 层序号是,1层表示包含所有节点的层,之后越大的层包含节点越少
zskiplistLevel
内包含两个属性,其中span属性表示通过 forward指针,跨过了底层的几个节点连接到当前层的下一个节点,在有序集合中,节点的rank,就是通过累加span来计算出来的- 和leve内的forward指针在一个node里可以有多个不同,一个node内只有一个backward指针,表示在最底层,指向上一个节点的指针
- 对于score,跳表是按照score的升序排列,如果分数一样,按照obj对象的字典序排序(字典序是:1 < 11 < 111 < 2 < 221 < 23,和js默认对数字的排序方式一样)
- robj *obj是一个指向字符串对象的指针,字符串对象内包含一个sds,字典序就是这个sds的字典序
redis内的使用
有序集合的实现之一,适用范围不广