跳跃表以及在redis中的应用

一、概述

跳跃表是一个随机化的数据结构,可以看做是二叉树的一个变种,它在性能上和红黑树,AVL树不想上下。目前在Reids和lucene的倒排索引文件中都有应用(后文会介绍跳跃表在这两种情况下的应用)。

二、原理

跳表的原理非常简单,跳表其实就是一种可以进行二分查找的有序链表。

        跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。首先在最高级索引上查找最后一个小于当前查找元素的位置,然后再跳到次高级索引继续查找,直到跳到最底层为止,这时候以及十分接近要查找的元素的位置了(如果查找元素存在的话)。由于根据索引可以一次跳过多个元素,所以跳查找的查找速度也就变快了。

        为了避免插入操作的时间复杂度是O(N),skiplist每层的数量不会严格按照2:1的比例,而是对每个要插入的元素随机一个层数。

        每一次插入一个新结点时,最好的做法就是根据当前表的结构得到一个合适的层数,插入后可以让跳跃表尽量接近理想的结构,但这在实现上会非常困难。Pugh 的论文中提出的方法是根据概率随机为新结点生成一个层数,具体的算法如下:
a.给定一个概率 p(p 小于 1),产生一个 [0,1) 之间的随机数;
b.如果这个随机数小于 p,则层数加 1;
c.重复以上动作,直到随机数大于概率 p(或层数大于程序给定的最大层数限制)。

 三、跳表特性

跳跃表是有序集合的底层实现之一;

Redis的跳跃表实现由zskiplist和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(比如表头节点、表尾节点、长度),而zskiplistNode则用于表示跳跃表节点;

每个跳跃表节点的层高都是1至32之间的随机数;

在同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的; 

跳跃表中的节点按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序;

跳表是一种实现起来很简单,单层多指针的链表,它查找效率很高,堪比优化过的二叉平衡树,且比平衡树的实现。

四、在redis中的应用

Redis使用跳跃表作为有序集合键的底层实现之一,如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员(member)是比较长的字符串时,Redis就会使用跳跃表来作为有序集合键的底层实现。

Redis的跳跃表实现由zskiplist和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(比如表头节点、表尾节点、长度),而zskiplistNode则用于表示跳跃表节点。

 zskipList

typedef struct zskiplist {
    // 表头节点和表尾节点
    struct zskiplistNode *header, *tail;
    // 表中节点的数量
    unsigned long length;
    // 表中层数最大的节点的层数
    int leval;
} zskiplist;

zskiplistNode

typedef struct zskiplistNode {
    // 后退指针
    struct zskiplistNode *backward;
    // 分值 权重
    double score;
    // 成员对象
    robj *obj;
    // 层
    struct zskiplistLevel {
        // 前进指针
        struct zskiplistNode *forward;
        // 跨度
        unsigned int span;
    } leval[];
} zskiplistNode;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值