首页 > 代码库 > 跳跃表,整数,压缩列表

跳跃表,整数,压缩列表

跳跃表事一种有序的结构,是有序集合键的底层实现

typedef struct zskiplistNode {

    // 后退指针
    struct zskiplistNode *backward;

    // 分值
    double score;

    // 成员对象
    robj *obj;

    //
    struct zskiplistLevel {

        // 前进指针
        struct zskiplistNode *forward;

        // 跨度
        unsigned int span;

    } level[];

} zskiplistNode;

跳跃表有两种结构定义的,一个是node,一个是list,list控制着node

node就是上面的结构,一个层,每个层有两个元素,一个是前进指针,一个是跨度。还有个后退指针,向后遍历的时候使用,跨度恒为1,还有一个分值和对象。分值就是从小到大依次向后的,doubleleixing类型,节点的对象成员是一个指针,指向一个sds。

 

list的结构:

head指向头

tail指向尾

lenght记录着跳跃表的长度

level记录着跳跃表内节点层数最高的那层

 

跨度的概念:

跨度不是用来便利的,是用来计算排位的,rank,通过跨度我们可以知道我们的某一个节点位于跳跃表的第几位

指向null的跨度都是0

 

 

整数集合:

 

typedef struct intset {

    // 编码方式
    uint32_t encoding;

    // 集合包含的元素数量
    uint32_t length;

    // 保存元素的数组
    int8_t contents[];

} intset;

整数集合是无重复的有序的,encoding是编码方式,有16,32,64位的,分别表示不同的范围,length代表的就是长度

因为底层实现是数组,所以有一个内置的数组,这个数组可以自动升级,当加进来的元素位数大于现有的就回自动升级,以最高的位标准,扩大内存,添加移动的时候从后向前进行

自动升级的好处就是

(1)增加灵活性

(2)节省内存,需要的时候扩展,一直秉承着最小对其原值

 

 

压缩列表

技术分享

 

 zlbytes:表示整个压缩列表占用的大小,重分配的时候下需要使用

zltail:计算列表的最后节点距离起始位置的距离,可以分方便的知道尾地址

zllen(2字节):记录节点个数,如果超过65535个的时候,我们需要自己遍历求解

中间都是每一个节点

zlend:0xff表示终止符

 

中间的entry节点是一个整数或者数组

都包含三个元素

previous_entry_length

前一个节点的长度

可能是一个字节或者是5个字节,如果前一个长度小于254个字节,那就是一个字节存,否则用5个字节,但是5个字节中,第一个字节为0XFE,表示是用5字节存储,后面4个字节表示的是实际长度

 

 

encoding:编码方式

可以表示字符或者整数,如果是字符的花,前面分别是00,01,10编码长度分别我1,2,5字节,所表示数组的长度也渐大

如果前面是11,只占一个字节,根据后6位的不同表示的整数的范围也不同

content:存储的数据

 

 

连锁更新:

如果每一个元素的大小都在250-253之间,突然增加一个元素,使得第一个+4,造成第二个长度+4,依次类推,这样的话需要进行n次重分配,每次的复杂度位n,那么时间复杂度最坏就是n的2次幂。尽管这样很糟糕,但是发生这种的情况不多,所以我们可以忽略不计

同理,删除一个元素的时候,也有可能造成类似的连锁更新

跳跃表,整数,压缩列表