(一)跳跃表数组
跳跃表是一种有序的数据结构,它经过每一个节点中维持多个指向其余节点的指针,从而达到快速访问节点的目的。数据结构
Redis使用跳跃表做为有序集合键的底层实现之一,若是一个有序集合包含的元素数量比较多,或者有序集合中元素的成员是比较长的字符串时,Redis就会使用跳跃表做为有序集合键的底层实现。学习
Redis中的两个地方用到了跳跃表,一个是实现有序集合键,另外一个是在集群节点中用做内部数据结构。ui
Redis的跳跃表由zskiplistNode 与 zskiplist 两个结构定义。其中zskiplistNode 结构用于标识跳跃表节点,zskiplist结构用于保存跳跃表节点的相关信息(表头、表尾节点、节点数量等)。编码
zskiplistNodespa
typedef struct zskiplistNode{ //层 struct zskiplistLevel{ struct zskiplistNode *forward;//前进指针 unsigned int span;//跨度 } level[]; //后退指针 struct zskiplistNode *backward; //分值 double score; //成员对象 robj *obj; }
层中包含多个元素,每一个元素是指向其余节点的指针,经过这些层能够加快访问其余节点的速度,层越多,访问其余节点的速度越快。没增长一个跳跃节点,程序根据幂次定律(越大的数出现几率越小)生成1-32之间的值做为层高。设计
一、每层都有一个指向表尾方向的前进指针,做为表头向表尾方向访问节点。指针
二、层中的跨度用于记录两个节点之间的距离。code
三、后退指针则只能一次跨1个节点进行访问。对象
四、跳跃表的排序是按照全部节点的分值来排序的。
五、节点中的对象则是保存了一个SDS的字符串。
六、同一个跳跃表的对象必须惟一,但分值能够重复。(相同分数,成员小的靠前排)。
跳跃表zskiplist
typedef struct zskiplist{ struct skiplistNode *header,*tail;//表头节点与表尾节点 unsigned long length;//表中节点的数量 int level;//表中层数最大的节点的层数(表头不计算在内) } zskiplist;
(二)整数集合
整数集合是集合键的底层实现之一,当一个集合只包含整数值元素,而且集合的元素数量很少时,Redis就会使用整数集合做为集合键的底层实现,而且保证集合中不会出现重复元素。
intset
typedef struct intset{ uint32_t encoding;//编码方式 uint32_t length;//集合包含的元素数量。 int8_t contents[];//保存元素的数组 } intset;
contents数组是这个数集合的底层实现:整数集合的每一个元素都是contents数组的一个数组项,各个项的数组中按值的大小从小到大有序地排列,而且数组中不包含任何重复项。
升级
当咱们要将一个新元素添加到整数集合里面时,而且新元素类型比整数集合现有的全部元素类型都长时,整数集合须要先进性升级,而后才能将新的元素添加到整数集合中。
一、根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间。
二、将底层数组现有的全部元素都转换为与新元素相同的类型,并将类型转换后的元素放置到正确位置上,并且在放置元素过程当中,须要继续维持底层数组的有序性质不变。
三、将新元素添加到底层数组里面。
四、修改整数集合encoding属性。
由于每次向整数集合添加新元素都有可能引发升级,而每次升级都须要将底层数组中已有的全部元素进行类型转换,因此向整数集合中添加新元素的时间复杂度为O(N);
---- end ----
天天学一点,总会有收获。
说明:尊重做者知识产权,文中内容参考《Redis设计与实现》,仅在此作学习与你们分享。