Redis源码(四)——跳跃表

跳跃表(skiplist)的定义与实现


  在对排行榜数据进行排序时,我们会用到Redis中的有序集合对象(sorted set),跳跃表就是有序集合的底层实现之一。跳跃表是一种有序的数据结构,每个节点中都维持着多个指向其他节点的指针,所以可以快速地访问节点。跳跃表的查找速度平均为O(logN),最差为O(N)。


  src下的redis.h中用zskiplistNode和zskiplist分别定义跳跃表节点以及跳跃表:

/* ZSETs use a specialized version of Skiplists*/
/*
 * 跳跃表节点
 */
typedef struct zskiplistNode {
 
    // 成员对象
    robj*obj;
 
    // 分值
    doublescore;
 
    // 后退指针
    structzskiplistNode *backward;
 
    // 层
    structzskiplistLevel {
 
        // 前进指针
       struct zskiplistNode *forward;
 
        // 跨度
       unsigned int span;
 
    }level[];
 
} zskiplistNode;

/*
 * 跳跃表
 */
typedef struct zskiplist {
 
    // 表头节点和表尾节点
    structzskiplistNode *header, *tail;
 
    // 表中节点的数量
   unsigned long length;
 
    // 表中层数最大的节点的层数
    intlevel;
 
} zskiplist;

zskiplistNode结构体中包含了以下属性:


1. 成员对象(obj)以及对应的分值(score):在跳跃表中,节点的成员变量是一个指向字符串对象的指针,且是唯一的;但分值是一个double类型,可以相同,跳跃表默认会以分值的大小递增排序,分值相同则根据成员对象的字典序进行排序


2. 后退指针backward:用于从表尾逆向访问各节点,每个节点只有一个后退指针


3. 层level[]:层是一个level数组,其内部保存着的结构体为zskiplistLevel。zskiplistLevel内有两个属性,前进指针forward以及跨度span。每个层都有指向表尾方向的前进指针,用于至后访问节点。跨度span则记录着两个节点之间的距离,可以用来计算节点在跳跃表中的排位(rank):在查找节点过程中,将访问过的所有层的跨度累加就是目标节点的排位。值得一提的是,在新建跳跃表节点时,其层数是通过幂次定律(越大的数生成几率越小)随机生成的一个介于1-32之间的值


跳跃表zskiplist中定义了表头节点及表尾节点、节点数目以及层数最大的节点的层数。因此用跳跃表访问表头及表尾节点的你复杂度均为O(1),这便省去了遍历的时间大大增强了效率。通过length属性也可以在O(1)时间内得到表中节点的数目

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值