跳跃表
typedef struct zskiplistNode {
struct zskiplistNode *backword; //后退指针
double score; //分值
robj *obj; //成员对象
struct zskiplistlevel { //层
struct zskiplistNode *forward; //前进指针
unsigned int span; //跨度
} level[];
} zskiplistNode;
1,层
每次创建一个新跳跃表节点的时候,程序都根据幂次定律随机生成一个介于1和32之间的值作为level数组的大小,即高度
2,前进指针
用于从表头向表尾方向访问节点。
3,跨度
用来计算排位(rank)的:在查找某个节点的过程中,将沿途访问过的所有层的跨度累计起来,得到的结果就是目标节点在跳跃表中的排位。
4,后退指针
从表尾向表头遍历跳跃表中所有节点
5,分值和成员
分值是double类型,节点成员对象是一个指向字符串对象的指针
跳跃表中的所有节点都按照分值从小到大来排序。
在同一个跳跃表中,各个节点保存的成员对象必须是唯一的,但是多个节点保存的分值却是可以相同的:
分值相同的节点按照成员对象在字典序的大小来进行排序。
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length; //节点的数量
int level; //表中层数最大的节点的层数
} zskiplist;
https://segmentfault.com/a/1190000013418471
为什么不用红黑树作为
- 实现比红黑树简单
- 比红黑树更容易扩展,作者之后实现zrank指令时没怎么改动代码。
- 红黑树插入删除时为了平衡高度需要旋转附近节点,高并发时需要锁。skiplist不需要考虑。
- 一般用zset的操作都是执行zrange之类的操作,取出一片连续的节点。这些操作的缓存命中率不会比红黑树低。