redis跳表的实现

本文介绍了Redis中跳表的实现,包括节点和跳表的结构体定义,以及增删节点的主要函数逻辑。还阐述了Redis跳表相比红黑树、Hash的优点,如可范围查询、操作简单、复杂度低、占用空间少、能快速计算节点rank等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了redis的跳表的源码,感觉代码的实现非常短小精悍。

redis中跳表主要实现:增删改查, 除了这几个常规功能之外,还有一个很牛逼且很实用的功能:获取节点的rank排名、或者获取指定范围rank的节点。

redis中跳表的实现

typedef struct zskiplistNode {

    robj *obj;      

    double score;       // 内部节点排序的依据,如果值相等根据obj对象排序。

    struct zskiplistNode *backward;        //后退指针。每次只能后退一个节点

    struct zskiplistLevel {

        struct zskiplistNode *forward;      //前进指针。一次可能跳过多个节点

        unsigned int span;               //跨度。 表示当前节点在当前层到达下一个节点的距离。后续查找节点的时候,每层会获取一个节点,这些节点的span加起来,就是节点的rank。

    } level[];                                    

} zskiplistNode;

 

typedef struct zskiplist {

    struct zskiplistNode *header, *tail;     //头结点和尾节点。tail是为了实现反向查找,即根据score从大到小的 顺序查找。注意header中的第一个节点是空节点。如果当前层的链为null,span表示链表的长度。header->forward节点的backward指向null。

    unsigned long length;            //节点的数量

    int level;                     //跳跃表中节点的最大层数。根据实际需要增加或者减小。因此每个节点level不同,分配的空间大小也不同。

} zskiplist;

 

主要函数:

zslInsert函数:添加一个节点

    update[ZSKIPLIST_MAXLEVEL]变量:每层待插入节点的上一个节点。

    rank[ZSKIPLIST_MAXLEVEL]变量:update[i]节点的rank,即链表头到update[i]节点的距离。

   函数主要逻辑:

   1.计算每层要插入节点的前一个节点,以及该节点的rank,这段代码实现的很精简,而且后续增删改查都用到。

   2.根据zslRandomLevel函数获取新结点的level,如果大于当前的最大level,新的level上第一个节点初始化。注意新的level上由于第一个节点的后继节点是NULL,即链表结尾,因此第一个节点的跨度为链表长度。

   3.创建新节点,更新每层中的链表关系和span。主要分2部分:一部分是底层要插入节点的level,这部分要更改update[i]节点在第i层和新插入节点的链表指针、span;第二部分由于没有插入节点,只要更改update[i]->level[i].span++

   4.如果新插入的节点是头节点或者尾节点,修改zskiplist

zslDelete函数:删除一个节点

  1.找到每层中要处理节点的前一个节点,保存在update[i]

  2.如果链表中存在该节点,检查每层中update[i]的下一个节点是不是要删除的节点,如果是则删除,并且update[i]对应的第i层的span要和下一个节点的span合并。如果不是,update[i]第i层的span-1

 

  其他功能的实现和上面两个函数的基本一致,这里不在赘述。

 

redis中跳表相比红黑树、hash的优点:

1.跳表和红黑树可以实现有序排列,即可以进行范围查询,hash只支持单值查询。

2.跳表的修改和删除的复杂度为O(n),redis中采用zslRandomLevel计算不同点的层次,不用严格维护上次节点是下层节点一半数量,将复杂度降低为O(logn)。虽然和红黑树的时间复杂度相等,但是实际操作中不需要考虑树的维护,只要处理相邻的节点指针,操作简单快速。

3.算法的远比红黑树简单的多。

4.redis中获取某段范围的节点,红黑树根据中序遍历,跳表只需要根据链表指针顺序读取,执行速度和实现复杂度都优于红黑树

5.redi的跳表跳表平均每个节点有1.33个指针(根据zslRandomLevel计算平均指针数量),红黑树至少有2个,占用空间少一些。

6.redis的跳表维护了span字段,可以快速计算出节点的rank或者获取指定rank的节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值