跳跃表

有序集合在生活中较常见,如根据成绩对学生进行排名、根据得分对游戏玩家进行排名等。对于有序集合的底层实现,我们可以使用数组、链表、平衡树等结构。数组不便于元素的插入和删除;链表的查询效率低,需要遍历所有元素;平衡树或者红黑树等结构虽然效率高但实现复杂。Redis采用了一种新型的数据结构——跳跃表。跳跃表的效率堪比红黑树,然而其实现却远比红黑树简单。

数据结构

在这里插入图片描述

从图中可以看到, 跳跃表主要由以下部分构成:

  • 表头(head):负责维护跳跃表的节点指针。
  • 跳跃表节点:保存着元素值,以及多个层。
  • 层:保存着指向其他元素的指针。高层的指针越过的元素数量大于等于低层的指针,为了提高查找的效率,程序总是从高层先开始访问,然后随着元素值范围的缩小,慢慢降低层次。
  • 表尾:全部由 NULL 组成,表示跳跃表的末尾。

搜索

跳表的核心思想是**“剪枝”**,具体是如下方式实现
如果是一个简单的链表,那么我们知道在链表中查找一个元素I的话,需要将整个链表遍历一次。

如果是说链表是排序的,并且节点中还存储了“跳跃”的指向后续节点的指针的话,那么在查找一个节点时,仅仅需要遍历N/2个节点即可。

一次典型的skiplist上的查找路径展示
在这里插入图片描述

redis中为啥不用红黑树二用跳表

  1. 内存占用方面跳表比红黑树多,但是多的内存很有限
  2. 实现比红黑树简单
  3. 跟红黑树更方便的支持范围查询

跳跃表节点与结构

/* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode {
    sds ele;// 用于存储字符串类型的数据
    double score;//用于存储排序的分值
    struct zskiplistNode *backward; // 后退指针,只能指向当前节点最底层的前一个节点,头节点和第一个节点——backward指向NULL,从后向前遍历跳跃表时使用
    struct zskiplistLevel {
        struct zskiplistNode *forward;//指向本层下一个节点,尾节点的forward指向NULL。
        unsigned long span;//forward指向的节点与本节点之间的元素个数。span值越大,跳过的节点个数越多。
    } level[];//为柔性数组。每个节点的数组长度不一样,在生成跳跃表节点时,随机生成一个1~64的值,值越大出现的概率越低。
} zskiplistNode;

跳跃表是Redis有序集合的底层实现方式之一,所以每个节点的ele存储有序集合的成员member值,score存储成员score值。所有节点的分值是按从小到大的方式排序的,当有序集合的成员分值相同时,节点会按member的字典序进行排序。

跳跃表的应用

在Redis中,跳跃表主要应用于有序集合的底层实现(有序集合的另一种实现方式为压缩列表)

Redis的配置文件中关于有序集合底层实现的两个配置:

  1. zset-max-ziplist-entries 128:zset采用压缩列表时,元素个数最大值。默认值为128。
  2. zset-max-ziplist-value 64:zset采用压缩列表时,每个元素的字符串长度最大值。默认值为64。

zset添加元素的主要逻辑位于t_zset.c的zaddGenericCommand函数中。zset插入第一个元素时,会判断下面两种条件:

  • zset-max-ziplist-entries的值是否等于0;
  • zset-max-ziplist-value小于要插入元素的字符串长度。

满足任一条件Redis就会采用跳跃表作为底层实现,否则采用压缩列表作为底层实现方式。

一般情况下,不会将zset-max-ziplist-entries配置成0,元素的字符串长度也不会太长,所以在创建有序集合时,默认使用压缩列表的底层实现。
zset新插入元素时,会判断以下两种条件:

  • zset中元素个数大于zset_max_ziplist_entries;
  • 插入元素的字符串长度大于zset_max_ziplist_value。

当满足任一条件时,Redis便会将zset的底层实现由压缩列表转为跳跃表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值