原理: 在每个节点中维持多个指向其他节点的指针。达到接近二分查找的目的
大部分情况下,跳跃表的执行效率与平衡数相媲美
当LinkedHashSet 中
1 元素数目过多 或者 2 成员是过长的字符串
使用跳跃表作为有序集合键的底层实现。
跳表在Redis中的应用:
1实现有序集合键
2在集群节点中用作内部数据结构
涉及到两个结构体:
1 zskiplistNode 用于表示跳跃表的节点
2 zskiplist 用于保存跳跃表节点的相关信息,如节点的数量、表头节点指针、表尾节点指针
typedef struct zskiplist{
structz skiplistNode *header,*tail; //表头 表尾指针
// 节点数目
unsigned long length;
// 表中层数最大的节点的层数
int level;
}zskiplist;
其中length 不包含表头节点
level 层数不包含表头节点
用L1、L2、L3 标记每个层,L1代表第一层,L2代表第二层,以此类推
每个层包含两个属性:
1前进指针 用于访问表尾方向的其他节点
2跨度 记录前进指针指向节点与当前节点的距离
后退指针:指向位于当前节点的前一个节点。用于程序从表尾向表头遍历
分值:score 每个节点会被分配一个分值,用作节点排序的指标,从小到大排序
typedef struct zskiplistNode {
struct zskiplistNode *backward; //后退指针
double score; //分值
robj *obj; //成员对象
// 层
struct zskiplistLevel {
struct zskiplistNode *forward; //前进指针
unsigned int span; //跨度
} level[]; //层数组,用于加快查询速度,理论上层越多访问速度越快
}zskiplistNode;
根据幂等定律随机给一个节点生成一个介于1到32之间的值作为层数组的大小,也就是层的高度。
值越小,其层数越多,过滤效率越高
使用前进指针实现有序集合的遍历
跨度是用来计算排位的,在查找某个节点的过程中,将沿途访问的所有层的跨度相加,就可以得到目标节点score的排名
成员对象是一个指针 *obj指向一个字符串对象SDS
每个跳表节点都有一个score,节点按照score从小到大排序。节点间的score可以相同,但是成员对象必然唯一(Set特性)
当score相同时,按照成员对象在字典序中的顺序进行排序。