共计 1286 个字符,预计需要花费 4 分钟才能阅读完成。
跳跃表
跳跃表(skiplist
)是一种 有序 数据结构,它通过 在每个字节中维持多个指向其它节点的指针,从而达到快速访问节点的目标。
跳跃表是在有序链表的根底上实现的。
在有序链表中,查找元素时,只能逐个查找,工夫复杂度为 O(N),操作非常迟缓。为了优化,能够思考在链表其中的元素上建索引的形式,就失去了链表。
跳跃表在 节点查问的工夫复杂度均匀为 O(logN),最坏状况下 O(N),还能够通过程序性操作来批量解决节点。
在大部分状况下,跳跃表的效率能够和均衡树相媲美,并且因为跳跃表的实现比均衡树要来得更为简略,所以有不少程序都应用跳跃表来代替均衡树。
Redis 应用 跳跃表作为有序汇合键的底层实现之一,如果一个有序列表蕴含的元素数量比拟多,又或者有序汇合中元素的成员是比拟长的字符串时,Redis 就会应用跳跃表来作为有序汇合键的底层实现。
Redis 只在两个中央用到了跳跃表,一个是实现有序汇合键,另一个是在集群节点中用作外部数据结构。
跳跃表的实现
跳跃表节点
typedef struct zskiplistNode {
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned int span;
} level[];
struct zskiplistNode *backward;
double score;
robj *obj;
} zskiplistNode;
-
level
: 蕴含多个元素,每个元素都蕴含一个指向其它节点的指针,程序能够通过这些层来放慢拜访其它节点的速度,一般来说,层的数量越多,拜访其它节点的速度就越快;每次创立一个新跳跃表节点的时候,程序都依据幂次定律随机生成一个介于 1 和 32 之间的值作为
level
数组的大小,这个大小就是层的“高度”forward
: 每个层都有一个指向表尾方向的后退指针,用于从表头向表尾方向拜访节点。span
: 代表层的跨度,用于记录两个节点之间的间隔。两个节点之间的跨度越大,它们相距就越远;指向 null 的所有后退指针的跨度都为 0,因为它们没有连向任何节点。
backward
: 节点的后退指针用于从表尾想表头方向拜访节点。跟能够一次跳过多个节点的后退指针不同,因为每个结点只有一个后退指针,所以每次只能后退至前一个节点。score
: 跳跃表的所有节点都按分值从小到大来排序。obj
: 是一个指针,指向一个字符串对象,而字符串对象则保留着一个 SDS 值。
在同一个跳跃表中,各个节点保留的成员对象必须是惟一的,然而多个节点保留的分值却是能够雷同的。分值雷同的节点将依照成员对象在字典序中的大小来进行排序,成员对象较小的节点会排在后面(凑近表头的方向),而成员对象较大的节点则会排在前面(凑近表尾的方向)。
跳跃表
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
header
: 指向跳跃表的表头指针tail
: 指向跳跃表的表尾指针length
: 记录节点的数量level
: 记录跳跃表中层数最大的节点的层数
正文完