蔚来真题:Redis跳跃表是如何添加元素的?

news/2024/11/17 5:27:29/

今天分享的这道题来自于蔚来的真实面试题。

Java 面试不可能不问 Redis,问到 Redis 不可能不问 Redis 的常用数据类型,问到 Redis 的常用数据类型,不可能不问跳跃表,当问到跳跃表经常会被问到跳跃表的查询和添加流程,所以接下来我们一起来看这道题的答案吧。

Redis 有序集合 ZSet 是由 ziplist (压缩列表) 或 skiplist (跳跃表) 组成的。

  1. 压缩列表 ziplist 本质上就是一个字节数组,是 Redis 为了节约内存而设计的一种线性数据结构,可以包含多个元素,每个元素可以是一个字节数组或一个整数。
  2. 跳跃表 skiplist 是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均 O(logN)、最坏 O(N) 复杂度的节点查找,还可以通过顺序性操作来批量处理节点。

跳跃表介绍

跳跃表 Skip List,也称之为跳表,是一种数据结构,用于在有序元素的集合中进行高效的查找操作。它通过添加多层链表的方式,提供了一种以空间换时间的方式来加速查找。

跳跃表由一个带有多层节点的链表组成,每一层都是原始链表的一个子集。最底层是一个完整的有序链表,包含所有元素。每个更高层级都是下层级的子集,通过添加额外的指针来跳过一些元素。这些额外的指针称为“跳跃指针”,它们允许快速访问更远的节点,从而减少了查找所需的比较次数。

跳跃表的平均查找时间复杂度为 O(log n),其中 n 是元素的数量。这使得它比普通的有序链表具有更快的查找性能,并且与平衡二叉搜索树(如红黑树)相比,实现起来更为简单。

简单的跳跃表如下图所示: 

跳跃表添加流程

前置知识:节点随机层数

在开始讲跳跃表的添加流程之前,必须先搞懂一个概念:节点的随机层数。 所谓的随机层数指的是每次添加节点之前,会先生成当前节点的随机层数,根据生成的随机层数来决定将当前节点存在几层链表中。

为什么要这样设计呢?

这样设计的目的是为了保证 Redis 的执行效率。

为什么要生成随机层数,而不是制定一个固定的规则,比如上层节点是下层跨越两个节点的链表组成,如下图所示: 

如果制定了规则,那么就需要在添加或删除时,为了满足其规则,做额外的处理,比如添加了一个新节点,如下图所示:

这样就不满足制定的上层节点跨越下层两个节点的规则了,就需要额外的调整上层中的所有节点,这样程序的效率就降低了,所以使用随机层数,不强制制定规则,这样就不需要进行额外的操作,从而也就不会占用服务执行的时间了。

添加流程

Redis 中跳跃表的添加流程如下图所示:

  1. 第一个元素添加到最底层的有序链表中(最底层存储了所有元素数据)。
  2. 第二个元素生成的随机层数是 2,所以再增加 1 层,并将此元素存储在第 1 层和最低层。
  3. 第三个元素生成的随机层数是 4,所以再增加 2 层,整个跳跃表变成了 4 层,将此元素保存到所有层中。
  4. 第四个元素生成的随机层数是 1,所以把它按顺序保存到最后一层中即可。

其他新增节点以此类推。

随机层数源码分析

随机层数的源码在 t_zset.c/zslRandomLevel(void) 中,如下所示:

int zslRandomLevel(void) {int level = 1;while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))level += 1;return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

从源码可知,随机层数有 50% 的概率被分配到 Level 1,25% 的概率被分配到 Level 2,12.5% 的概率被分配到 Level 3,以此类推。

Redis 跳跃表默认允许最大的层数是 32,此值在 ZSKIPLIST_MAXLEVEL 源码中被定义。

小结

跳跃表是由多个有序的链表组成的,最底层存储了所有元素的数据,这样存储让它的查询效率更高,查询复杂度从 O(n) 变为了 O(log n)。跳跃表的添加流程是根据节点生成的随机层数,将它插入到最底层节点和上层的 N-1 层节点中,描述添加流程的关键就是理解随机层数以及其背后的原理。


http://www.ppmy.cn/news/668383.html

相关文章

学习node.js模块机制

一、CommonJS的模块规范 Node与浏览器以及 W3C组织、CommonJS组织、ECMAScript之间的关系 Node借鉴CommonJS的Modules规范实现了一套模块系统&#xff0c;所以先来看看CommonJS的模块规范。 CommonJS对模块的定义十分简单&#xff0c;主要分为模块引用、模块定义和模块标识3…

30强争夺战即将开启 巅峰对决一触即发

在飞速发展的技术和激烈的市场竞争中&#xff0c;企业必须不断的进步才有机会在市场中续存下去。为了帮助国内的电子产业链条当中的相关企业&#xff0c;在面对经济全球化及日新月异的用户需求中能够不断的做大做强&#xff0c;慧聪电子网、慧聪芯城联合举办了第三届HCFT智能硬…

正则十八式-第三式:龙跃于渊

少年&#xff0c;见你骨骼精奇&#xff0c;是百年一遇的练武奇才&#xff0c;你我又是有缘人&#xff0c;随为师修炼吧 正则十八式-第一式&#xff1a;直捣黄龙正则十八式-第二式&#xff1a;控鹤擒龙正则十八式-第三式&#xff1a;龙跃于渊正则十八式-第四式 挫骨扬灰 接上篇:…

你学习了Python,再看此文,这是一篇可以给你带来外快的文章,不夸张

这次文章为什么这么慢&#xff1f;是因为上周铲屎官独自撇下皮克啪&#xff0c;飞去日本给女朋友过18岁生日&#xff0c;浪了几天&#xff0c;啊哈哈哈哈。 这几天明显&#xff0c;北京的会开完了&#xff0c;空气质量&#xff0c;呵呵&#xff0c;呵呵呵呵。 那么这期我们来聊…

【渝粤题库】陕西师范大学201591 中国古代文学(二)作业(高起本)

《中国古代文学&#xff08;二&#xff09;》高起本作业 一、单项选择题 1.建安作家中&#xff0c;留存作品最多、成就最大的作家是&#xff1a; A曹操 B曹丕 C曹植 D王粲 E蔡琰 2&#xff0e;“骨气奇高&#xff0c;词采华茂”是《诗品》对下列哪位诗人作出的评价&#xff1a;…

webrtc 支持H265(二) ZLMediaKit通过datachannel通道转发视频流

webrtc datachannel的协商 ZLMediaKit支持webrtc接入&#xff0c;按正常流程&#xff0c;第一步需要协商出音视频通道。 但方案是只协商出datachannel&#xff0c;sdp如下&#xff1a; web 发起offer: v0^M o- 7161281774595815373 2 IN IP4 127.0.0.1^M s-^M t0 0^M agroup:…

SpringBoot2+Vue2实战(六)登录,注册实现及自定义异常处理,个人信息页面与昵称头像功能实现

一、登录&#xff1a; UserDto Data public class UserDto {private String username;private String password;Alias("nickname")private String nickname;private String avatarUrl; }UserController //登录PostMapping("/login")public Result login(R…

mybatis模拟05

SqlSession 添加 selectOne(String sqlId, Object data) method /*** description 查询一条数据* param sqlId&#xff1a;sql 语句的 id* param data:所需要的数据 * return result 查询结果*/ public Object selectOne(String sqlId, Object data){return null; } 实现 …