当前位置: 首页 > news >正文

Redis数据结构:List类型全面解析

文章目录

  • 一、List数据类型
    • 1.1 简介
    • 1.2 应用场景
    • 1.3 底层结构
  • 二、数据结构
    • 2.1 压缩列表ZipList
    • 2.2 双向链表LinkedList(后续已废弃)
    • 2.3 快速链表QuickList
  • 三、List常见命令

在这里插入图片描述

一、List数据类型

1.1 简介

详细介绍:Redis五种数据类型、String、List、Set、Hash、ZSet

Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构,按插入顺序排序,你可以添加一个元素到头部(左边)或尾部(右边)。在 Redis 中,列表最多可以包含 2^32 - 1 个元素。既可以支持正向检索和也可以支持反向检索。特征也与LinkedList类似:

  • 有序
  • 元素可重复
  • 插入和删除快
  • 查询速度一般。

1.2 应用场景

根据 Redis 双向列表的特性,因此其也被用于异步队列的使用。实际开发中将需要延后处理的任务结构体序列化成字符串,放入 Redis 的队列中,另一个线程从这个列表中获取数据进行后续处理。

  • 消息队列:可以利用 List 的 push 和 pop 操作,实现生产者消费者模型。
  • 时间线、动态消息:比如微博的时间线,可以将最新的内容放在 List 的最前面。
  • 常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等

1.3 底层结构

  • 在3.2版本之前,Redis List底层采用压缩链表ZipList双向链表LinkedList来实现List。当元素数量小于512并且元素大小小于64字节时采用ZipList编码,超过则将自动采用LinkedList编码
  • 在3.2版本之后,Redis统一采用快速链表QuickList来实现List

二、数据结构

Redis的List结构类似一个双端链表,可以从首、尾操作列表中的元素:

  • 在Redis 3.2版本之前,Redis List底层采用压缩链表ZipList双向链表LinkedList来实现List。当元素数量小于512个并且元素大小小于64字节时采用ZipList编码,超过则将自动采用LinkedList编码。
  • 在3.2版本之后,Redis统一采用快速链表QuickList结构来实现List

QuickList结构如下:

在这里插入图片描述

在这里插入图片描述

在 Redis3.2 版本前,Redis 列表 List 使用两种数据结构作为底层实现:

  • 压缩列表 ZipList:插入元素过多或字符串太大,就需要调用 Realloc 扩展内存;
  • 双向链表 LinkedList:需附加指针 Prev 和 Next,较浪费空间,加重内存的碎片化

2.1 压缩列表ZipList

在 Redis3.2 版本前 压缩列表不仅是 List 的底层实现之一,同时也是 Hash、 ZSet 两种数据类型底层实现之一。

ZipList是一种特殊的“双端链表”(并非链表),由一系列特殊编码的连续内存块组成,像内存连续的数组。可以在任意一端进行压入/弹出操作,并且该操作的时间复杂度为O(1)。

在这里插入图片描述

压缩列表 底层数据结构:本质是一个数组,增加了列表长度、尾部偏移量、列表元素个数、以及列表结束标识,有利于快速寻找列表的首尾节点;但对于其他正常的元素,如元素2、元素3,只能一个个遍历,效率仍没有很高效。

当我们的 List 列表数据量比较少的时候,且存储的数据轻量的(如小整数值、短字符串)时候, Redis 就会通过压缩列表来进行底层实现。

在这里插入图片描述

2-5

属性类型长度说明
zlbytesuint32_t4字节一个 4 字节的整数,表示整个压缩列表占用的字节数量,包括 <zlbytes> 自身的大小
zltailuint32_t4字节一个 4 字节的整数,记录压缩列表表尾节点距离压缩列表的起始地址有多少字节,通过这个偏移量,可以确定表尾节点的地址
zllenuint16_t2字节一个 2 字节的整数,表示压缩列表中的节点数量。最大值为UINT16_MAX(65534),如果超过这个数,此处会记录为65535,但节点的真实数量需要遍历整个压缩列表才能计算出
entry列表节点不定压缩列表中的元素,每个元素都由一个或多个字节组成,节点的长度由节点保存的内容决定。每个元素的第一个字节(又称为"entry header")用于表示这个元素的长度以及编码方式
zlenduint8_t1字节一个字节,特殊值0xFF(十进制255),表示压缩列表的结束

在这里插入图片描述

注意:

  • 如果查找定位首个元素或最后1个元素,可以通过表头 “zlbytes”、“zltail_offset” 元素快速获取,复杂度是 O(1)。但是查找其他元素时,就没有这么高效了,只能逐个查找下去,比如 entryN 的复杂度就是 O(N)

  • ZipList虽然节省内存,但申请内存必须是连续空间,如果内存占用较多,申请效率较低。

2.2 双向链表LinkedList(后续已废弃)

LinkedList 是标准的双向链表,Node 节点包含 prev 和 next 指针,分别指向后继与前驱节点,因此从双向链表中的任意一个节点开始都可以很方便地访问其前驱与后继节点。

在这里插入图片描述

LinkedList 可以进行双向遍历;添加删除元素快 O(1),查找元素慢 O(n),高效实现了 LPUSH 、RPOP、RPOPLPUSH,但由于需要为每个节点分配额外的内存空间,所以会浪费一定的内存空间。这种编码方式适用于元素数量较多或者元素较大的场景。

LinkedList 结构为链表提供了表头指针 head、表尾指针 tail,以及节点数量计算 len。下图展示一个由 list 结构和三个 listNode 节点组成的链表:

在这里插入图片描述

Redis 的链表实现的特性可以总结如下:

  • 双端:链表节点带有 prev 和 next 指针,获取某个节点的前一节点和后一节点的复杂度都是 O(1);
  • 无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问以 NULL 为终点;
  • 表头指针/表尾指针:通过 list 结构的 head 指针和 tail 指针,获取链表的表头节点和表尾节点的复杂度为 O(1);
  • 链表长度计数器:通过 list 结构的 len 属性来对 list 的链表节点进行计数,获取节点数量的复杂度为O(1);
  • 多态:链表节点使用 void* 指针来保存节点值,并通过 list 结构的 dup、free、match 三个属性为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值。
  • 使用链表的附加空间相对太高,因为 64bit 系统中指针是 8 个字节,所以 prev 和 next 指针需要占据 16 个字节,且链表节点在内存中单独分配,会加剧内存的碎片化,影响内存管理效率

2.3 快速链表QuickList

QuickList底层 LinkedList + ZipList,可以从双端访问,内存占用较低,保含多个ZipList,存储上限高。其特点:

  • 是一个节点为ZipList的双端链表
  • 节点采用ZipList,解决了传统链表的内存占用问题
  • 控制了ZipList大小,解决连续内存空间申请效率问题
  • 中间节点可以压缩,进一步节省了内存

在这里插入图片描述

ZipList虽然节省内存,但申请内存必须是连续空间,如果内存占用较多,申请效率较低。

2-10

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、List常见命令

List的常见命令有

  • LPUSH key value [value …] :向列表左侧插入一个或多个元素
  • LPOP key :移除并返回列表左侧的第一个元素,没有则返回nil
  • RPUSH key value [value …] :向列表右侧插入一个或多个元素
  • RPOP key :移除并返回列表右侧的第一个元素
  • LRANGE key start stop:返回一段角标范围内的所有元素
  • BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
  • lindex key index:通过下标获得list当中的某一个值
  • llen key:获取list的长度

在这里插入图片描述

  • 如何利用List结构模拟一个栈?

    • 入口和出口在同一边
  • 如何利用List结构模拟一个队列?

    • 入口和出口在不同边
  • 如何利用List结构模拟一个阻塞队列?

    • 入口和出口在不同边
    • 出队时采用BLPOP或BRPOP
127.0.0.1:6379> lpush list1 18 20 Jenny       #向列表左侧插入一个或多个元素
(integer) 3
127.0.0.1:6379> lpush list1 Happy
(integer) 4
127.0.0.1:6379> lrange list1 0 2              #返回一段角标范围内的所有元素
1) "Happy"
2) "Jenny"
3) "20"
127.0.0.1:6379> rpush list1 Jack Health 16    #向列表右侧插入一个或多个元素
(integer) 7
127.0.0.1:6379> lrange list1 0 -1             #通过区间获取具体的值
1) "Happy"
2) "Jenny"
3) "20"
4) "18"
5) "Jack"
6) "Health"
7) "16"
127.0.0.1:6379> lpop list1                   #移除list的第一个元素:Happy
"Happy"
127.0.0.1:6379> rpop list1                   #移除list的最后一个元素:16
"16"
127.0.0.1:6379> lindex list1 2               #通过下标获得list当中的某一个值
"18"
127.0.0.1:6379> llen list1                   #获取list的长度
(integer) 5
127.0.0.1:6379> rpush list1 18 Jack
(integer) 7
127.0.0.1:6379> lrange list1 0 -1
1) "Jenny"
2) "20"
3) "18"
4) "Jack"
5) "Health"
6) "18"
7) "Jack"
127.0.0.1:6379> lrem list1 2 Jack           #移除list集合指定个数的value,移除2个值为Jack的,精确匹配
(integer) 2
127.0.0.1:6379> lrange list1 0 -1
1) "Jenny"
2) "20"
3) "18"
4) "Health"
5) "18"
127.0.0.1:6379> ltrim list1 3 4            #截取list集合中下标为3到下标为4之间的元素集合,并覆盖原来的list集合
OK
127.0.0.1:6379> lrange list1 0 -1
1) "Health"
2) "18"
127.0.0.1:6379> lset list 1 17
(error) ERR no such key
127.0.0.1:6379> lset list1 1 17           #更新list集合当中下标为1的值为17,如果下标1的值不存在,则报错
OK
127.0.0.1:6379> linsert list1 AFTER Health 20    #将某个具体的值插入到某一个具体元素(默认第一个)的前面或者后面
(integer) 3
127.0.0.1:6379> linsert list1 BEFORE Health Jenny
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "Jenny"
2) "Health"
3) "20"
4) "17"

在这里插入图片描述

参考 Redis基础(超详解)一 :Redis定义、SQL与NoSQL区别、Redis常用命令、Redis五种数据类型、String、List、Set、Hash、ZSet;Redis的Java客户端 、Redis数据结构:List类型全面解析

相关文章:

Redis数据结构:List类型全面解析

文章目录 一、List数据类型1.1 简介1.2 应用场景1.3 底层结构 二、数据结构2.1 压缩列表ZipList2.2 双向链表LinkedList&#xff08;后续已废弃&#xff09;2.3 快速链表QuickList 三、List常见命令 一、List数据类型 1.1 简介 详细介绍&#xff1a;Redis五种数据类型、Strin…...

人工智能证书合集

本文将对目前市面上主流官方机构颁发的人工智能证书进行整理和介绍&#xff0c;由于整理的证书较多&#xff0c;本文共一万八千多字&#xff0c;请根据自己的考证需求阅读对应部分的内容&#xff0c;希望本文对人工智能行业的从业人员和计划从事人工智能相关岗位工作的人员有所…...

php开发实战分析(8):优化MySQL分页查询与数量统计,提升数据库性能

在开发过程中&#xff0c;我们遇到了一段用于从数据库中查询部门信息的PHP代码。该代码负责根据不同的条件&#xff08;如部门名称和来源&#xff09;筛选数据&#xff0c;并返回分页结果及总记录数。然而&#xff0c;原始代码存在一些问题&#xff0c;包括重复的查询条件构建逻…...

shell脚本案例:RAC配置多路径时获取磁盘设备WWID和磁盘大小

使用场景 在RAC配置多路径时&#xff0c;需要获取到磁盘设备的wwid。因为RAC的磁盘配置是提前规划好的&#xff0c;只知道wwid&#xff0c;不知道磁盘对应大小&#xff0c;是不知道应该如何配置多路径的mutipath.conf文件的&#xff1b;而凭借肉眼手工去对应磁盘设备的wwid和大…...

Android Framework AMS(10)广播组件分析-1

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读应用层广播组件的发送广播和接收处理广播 2个过程&#xff0c;以及从APP层到AMS调用之间的打通。关注思维导图中左上部分即可。 有…...

在 Node.js 中使用 .env 文件

什么是 .env 文件&#xff1f; 文件.env是包含环境变量键值对的简单文本文件。此文件的内容不会被签入源代码管理&#xff0c;从而确保敏感数据的安全。 示例 PORT 4000 DATABASE_URL mongodb://localhost: 27017 /mydb API_KEY abcd1234 NODE_ENV development 在 Node.…...

CesiumJS 案例 P19:添加矩形、监听鼠标左击、监听鼠标右击、监听鼠标移动

CesiumJS CesiumJS API&#xff1a;https://cesium.com/learn/cesiumjs/ref-doc/index.html CesiumJS 是一个开源的 JavaScript 库&#xff0c;它用于在网页中创建和控制 3D 地球仪&#xff08;地图&#xff09; 一、添加矩形 <!DOCTYPE html> <html lang"en&…...

路测毫米波雷达标定和目标跟踪

1 2 3 4 5 6 查找匹配时&#xff0c;先对数据排序。逐帧对数据处理&#xff0c;运行速度快。单帧有噪点&#xff0c;多帧处理&#xff0c;准确率更高一些。 7 8 9 10 参考 路侧毫米波雷达标定与目标跟踪哔哔哩_bilibili路侧毫米波雷达标定与目标跟踪, 视频播放量 5855、弹幕量…...

【sqlmap使用手册-持续更新中】

SQLMap 简介 SQLMap 是一个开源的渗透测试工具&#xff0c;用于自动化检测和利用 SQL 注入漏洞。它支持多种数据库&#xff0c;包括 MySQL、PostgreSQL、Oracle、SQL Server 等。 可以通过以下命令安装sqlmap git clone https://github.com/sqlmapproject/sqlmap.git最常用的…...

面向对象三大特征之一:封 装

1、特点 封装是面向对象的核心思想&#xff0c;两层含义&#xff1a;一是一个整体&#xff08;把对象的属性和行为看成一个整体&#xff0c;即封装在一个对象种&#xff09;&#xff0c;二是信息隐藏&#xff0c;对外隐藏&#xff0c;但可以通过某种方式进行调用。 2、访问权…...

qt QMenuBar详解

1、概述 QMenuBar是Qt框架中用于创建菜单栏的类&#xff0c;它继承自QWidget。QMenuBar通常位于QMainWindow对象的标题栏下方&#xff0c;用于组织和管理多个QMenu&#xff08;菜单&#xff09;和QAction&#xff08;动作&#xff09;。菜单栏提供了一个水平排列的容器&#x…...

ESP32的下的蓝牙应用笔记(1)——Beacon蓝牙信标

Beacon蓝牙信标简介 ‌Beacon蓝牙信标‌是一种基于蓝牙低功耗&#xff08;BLE&#xff09;技术的设备&#xff0c;主要用于提供位置信息和数据传输服务。它通过周期性地广播信号&#xff0c;能够在一定范围内与其他蓝牙设备进行通信&#xff0c;从而提供精准的位置信息和相关服…...

控制台安全内部:创新如何塑造未来的硬件保护

在 Help Net Security 的采访中&#xff0c;安全研究人员 Specter 和 ChendoChap 讨论了游戏机独特的安全模型&#xff0c;并强调了它与其他消费设备的不同之处。 他们还分享了对游戏机安全性的进步将如何影响未来消费者和企业硬件设计的看法。 斯佩克特 (Specter) 是本周在阿…...

如何选择适合自己的 Python IDE

集成开发环境&#xff08;IDE&#xff09;是指提供广泛软件开发能力的软件应用程序。IDE 通常包括源代码编辑器、构建自动化工具和调试器。大多数现代 IDE 都配备了智能代码补全功能。在本文中&#xff0c;你将发现目前市场上最好的 Python IDE。 什么是 IDE&#xff1f; IDE…...

Matlab车牌识别课程设计报告模板(附源代码)

目 录 一&#xff0e;课程设计目的……………………………………………3 二&#xff0e;设计原理…………………………………………………3 三&#xff0e;详细设计步骤……………………………………………3 四. 设计结果及分析…………………………………………18 五. …...

kubesphere jenkins自动重定向 http://ks-apiserver:30880/oauth/authorize

问题&#xff1a;登陆kubesphere的jenkins Nodeport IP :Port 46.XXX.XXX.16:30180 自动跳转失败 http://ks-apiserver:30880/oauth/authorize?client_idjenkins&redirect_urihttp://46.XXX.XXX.16:30180/securityRealm/finishLogin&response_typecode&scopeopen…...

Vue3访问页面时自动获取数据

1. 使用生命周期钩子函数 # 后端代码--使用pywebview class Api:def greet(self):greet_text pywebview and vue3response {}response[text] greet_textreturn responseif __name__ __main__:# 前后端通信测试api Api()window webview.create_window(Vue app in pywebvie…...

go语言回调函数的使用

前言 在 Go 语言中&#xff0c;回调函数是一种将一个函数作为参数传递给另一个函数&#xff0c;在特定的事件发生时被调用的编程模式。 一、回调函数的定义 type OnTaskHandler func(r []byte)type remoteTaskClient struct {sync.RWMutexonTask OnTaskHandler } 以上定义了…...

区块链学习笔记(一)

区块链技术实现了去中心化的货币系统&#xff0c;与中心化记账方式不同&#xff0c;它消除了中间第三方&#xff0c;允许用户进行点对点交易&#xff0c;并确保了货币的真正所有权。此外&#xff0c;区块链的代码完全公开且不可篡改&#xff0c;保障了系统的透明度和安全性。 …...

解决QT打包发布App Store时(90238)错误

Invalid signature. The main app bundle, xxxx at the “xxxx.app” path, has the following signing error(s): [a sealed resource is missing or invalid. In subcomponent: xxxx.app/Contents/Frameworks/QtWebEngineCore.framework]. For details about signing Mac cod…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...