redis - 跳跃表详细介绍

    redis吸引很多人使用的一个重要的原因,就是它对众多数据类型的支持。包括string,hash,set,zset,list等五种数据对象。

    其中zset用来保证数据的有序存储,实现中,redis使用跳跃表和压缩列表,作为zset的底层实现。当元素数量比较多,或者元素成员是比较长的字符串时,底层实现采用跳跃表。


    跳跃表是什么?

    一种有序的数据结构,通过在节点中维持多个指向其它节点的指针,达到快速访问的目的。

      

    跳跃表的好处是什么? 

    1. 跟平衡树相比,实现简单;

    2. 平均复杂度为O(logN),最坏为O(N);

   

    跳跃表的数据结构由 zskiplistNode 和 zskiplist 两个结构定义,zskiplistNode表示跳跃表节点,zskiplist保存跳跃表节点的相关信息。

    

    zskiplistNode的数据结构如下:

   typedef struct zskiplistNode {

    robj *obj;

    double score;

    struct zskiplistNode *backward;

    struct zskiplistLevel {

        struct zskiplistNode *forward;

        unsigned int span;

     } level[];

   } zskiplistNode

    skiplistLevel包含多个元素,每个元素包含一个指向其它节点的前进指针,通过它来加快访问其它节点。每次创建一个跳跃表节点的时候,会随机生成一个值,该值介于1和32之间,作为level数组的大小。span表示层的跨度,用来计算最终的位置,程序在遍历时,会将沿途访问过的所有层的跨度累计,得出目标节点的对应位置;

    backward用于从表尾向表头访问节点;

    score 所有节点都按照它进行排序;

    obj 指向一个字符串对象;


    zskiplist的数据结构:  

    typedef struct zskiplist {

       struct zskiplistNode *header, *tail;

       unsigned long length;

       int level;

    } zskiplist;

   header,tail用来表示跳跃表的表头和表尾巴节点,length表示跳跃表的整体长度,level表示跳跃表的高度。

   zskiplist的主要作用,是可以方便的对整个跳跃表进行处理,比如获取跳跃表的整个长度的信息。

 

   跳跃表的层数如何生成?

   在插入的过程中构造,向跳跃表中插入一个数值,相当于在表中插入一列从起始跳跃表节点S出发,向上的一段数值,需要确定两个元素:数值的位置和层数。由于所有链是递增序列的方式,所以位置主要是根据对应数值的比较对出。而层数,程序会先记录比该节点小的值的span,然后,随机生成介于1和32之间的数值,作为该节点的层数,该算法主要是基于冥次定律,越大的数出现的概率越小。假设level为2的概率为P,则level为3的概率为p*p,以此类推。


   跳跃表查找的示例图:

  

wKiom1RiVkqQnE8hAAE8Ajga6lE999.jpg

   图中,表示有三个节点,他们对应的score分别为1,2,3,其中,虚线,代表在跳跃表中,查找score为2,成员对象为02的节点,在查找过程中,经过了两个span为1的节点,所以,可以得出该节点在跳跃表中的排位为2。 BW表示后退指针,实线的,表示节点间的span,由于节点间的关系比较多,所以只画了几个。

你可能感兴趣的:(redis,zset,跳跃表)