Redis系统-数据结构-02-链表

二、List(列表)

1、List 数据结构的必要性

List 是一种有序的数据结构,可以按顺序存储多个字符串。它的主要特点如下:

  1. 有序性:List 中的元素是有序的,可以通过索引访问。
  2. 双向操作:List 支持从两端进行操作(如插入和删除),非常灵活。
  3. 多用途:List 可以用作队列(FIFO)和栈(LIFO),适用于多种场景。

在实际应用中,List 非常适合用于需要保持顺序的数据存储,例如任务队列、聊天记录、时间线等。由于 Redis 的高性能特点,List 还可以处理大量的数据读写操作。

2、List 的底层实现

在 Redis 中,List 有两种底层实现方式:

  1. 压缩列表(ziplist)
  2. 快速列表(quicklist)
2.1 压缩列表(ziplist)

压缩列表是一种为节省内存而设计的紧凑型双向链表。它通过将多个元素压缩存储在一个连续的内存块中,减少了内存碎片,提高了内存利用率。

结构:

typedef struct {
    uint32_t zlbytes;    // ziplist 占用的总字节数
    uint32_t zltail;     // ziplist 表尾节点的偏移量
    uint16_t zlen;       // ziplist 中节点的数量
    unsigned char entries[];  // 数据项
} ziplist;

每个数据项(entry)包含:

  • prevrawlen:前一个数据项的长度
  • len:当前数据项的长度
  • data:实际存储的数据

压缩列表通过紧凑的内存布局来节省空间,非常适合存储少量数据或小数据量的场景。然而,由于压缩列表的连续内存结构,在插入和删除操作时需要移动大量数据,时间复杂度较高。

2.2 快速列表(quicklist)

为了弥补压缩列表在插入和删除操作上的不足,Redis 3.2 引入了快速列表(quicklist)。快速列表结合了压缩列表和双向链表的优点,是一种用于实现列表(List)类型的高效数据结构。每个快速列表节点(quicklistNode)包含一个压缩列表,实现了数据的紧凑存储和高效操作。

结构:

typedef struct quicklist {
    quicklistNode *head;      // 快速列表头节点
    quicklistNode *tail;      // 快速列表尾节点
    unsigned long count;      // 快速列表中的节点数量
    unsigned long len;        // 快速列表中的元素数量
    int fill : QL_FILL_BITS;  // 填充因子
    unsigned int compress : QL_COMP_BITS;  // 压缩深度
    quicklistBookmark bookmarks[];  // 书签
} quicklist;

typedef struct quicklistNode {
    struct quicklistNode *prev;   // 前一个节点
    struct quicklistNode *next;   // 后一个节点
    unsigned char *zl;            // 压缩列表
    unsigned int sz;              // 压缩列表大小
    unsigned int count : 16;      // 节点中元素数量
    unsigned int encoding : 2;    // 编码类型
    unsigned int container : 2;   // 容器类型
    unsigned int recompress : 1;  // 重新压缩标志
    unsigned int attempted_compress : 1;  // 尝试压缩标志
    unsigned int extra : 10;      // 额外空间
} quicklistNode;

快速列表通过将多个压缩列表节点(quicklistNode)连接成一个双向链表,使得在两端进行插入和删除操作非常高效。同时,压缩列表的紧凑存储方式也能保证较高的内存利用率。

3、List 的常用操作

Redis 提供了丰富的 List 操作命令,包括插入、删除、获取和修剪等操作。

插入操作
  • LPUSH key value [value ...]:在列表的左端插入一个或多个值。该命令会将一个或多个值插入到列表的左端(头部)。
  • RPUSH key value [value ...]:在列表的右端插入一个或多个值。该命令会将一个或多个值插入到列表的右端(尾部)。
删除操作
  • LPOP key:移除并返回列表的左端元素。该命令会移除并返回列表头部的元素。
  • RPOP key:移除并返回列表的右端元素。该命令会移除并返回列表尾部的元素。
获取操作
  • LINDEX key index:获取列表中指定索引的元素。该命令会返回列表中指定索引的元素。
  • LRANGE key start stop:获取列表中指定范围的元素。该命令会返回指定范围内的元素,start 和 stop 为索引。
修剪操作
  • LTRIM key start stop:对列表进行修剪,只保留指定范围内的元素。该命令会将列表修剪到指定范围之外的元素都会被删除。
4、List 的实现细节

创建 List 对象

robj *createQuicklistObject(void) {
    quicklist *l = quicklistCreate();
    robj *o = createObject(OBJ_LIST, l);
    o->encoding = OBJ_ENCODING_QUICKLIST;
    return o;
}

创建 quicklist 对象

quicklist *quicklistCreate(void) {
    struct quicklist *quicklist;
    quicklist = zmalloc(sizeof(*quicklist));
    quicklist->head = quicklist->tail = NULL;
    quicklist->len = 0;
    quicklist->count = 0;
    quicklist->compress = 0;
    quicklist->fill = -2;  // 默认填充因子
    quicklist->bookmark_count = 0;
    return quicklist;
}

创建 quicklistNode 对象

quicklistNode *quicklistCreateNode(void) {
    quicklistNode *node;
    node = zmalloc(sizeof(*node));
    node->prev = node->next = NULL;
    node->zl = NULL;
    node->sz = 0;
    node->count = 0;
    node->encoding = 0;
    node->container = 0;
    node->recompress = 0;
    node->attempted_compress = 0;
    node->extra = 0;
    return node;
}

压缩列表与快速列表的结合

// 创建一个新的 quicklist 对象
quicklist *quicklist = quicklistCreate();

// 创建一个新的 quicklistNode 对象
quicklistNode *node = quicklistCreateNode();

// 为 quicklistNode 分配一个新的压缩列表
node->zl = ziplistNew();
node->sz = ziplistBlobLen(node->zl);

// 将 node 插入到 quicklist 中
quicklist->head = node;
quicklist->tail = node;
quicklist->len = 1;
quicklist->count = ziplistLen(node->zl);
5、使用示例

以下是一些使用 Redis List 的示例,展示了如何利用 List 进行数据的存储和操作。

插入数据

LPUSH mylist "world"
# (integer) 1

LPUSH mylist "hello"
# (integer) 2

获取数据

LRANGE mylist 0 -1
# 1) "hello"
# 2) "world"

删除数据

LPOP mylist
# "hello"

LRANGE mylist 0 -1
# 1) "world"
结论

通过上述解析,我们可以更好地理解 List 的设计思想和实现原理,从而在实际开发中更好地利用 List 提供的优势。在 Redis 中,List 通过压缩列表和快速列表的结合,实现了高效的存储和操作,适用于多种场景如队列、栈和消息列表等。了解这些优化策略,可以帮助我们在实际应用中更好地利用 Redis 的性能和功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/780204.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

尚品汇-(十三)

&#xff08;1&#xff09;查询sku列表 在ManageService 中添加 /*** SKU分页列表* param pageParam* return*/ IPage<SkuInfo> getPage(Page<SkuInfo> pageParam);接口实现类 Override public IPage<SkuInfo> getPage(Page<SkuInfo> pageParam) {Qu…

【双一流高校主办,Springer-LNICST出版,EI稳定检索】2024年应用计算智能、信息学与大数据国际会议(ACIIBD 2024,7月26-28)

2024年应用计算智能、信息学与大数据国际学术会议&#xff08;ACIIBD 2024&#xff09;将于2024年7月26-28日在中国广州举办。会议将聚焦于计算智能及其应用、信息、大数据等相关的研究领域&#xff0c; 广泛邀请国内外知名专家学者&#xff0c;共同探讨相关学科领域的最新发展…

Ubuntu + SSH密钥连接服务器

1. 下载VS code cd到下载文件夹后&#xff0c;使用命令安装&#xff0c;把xxx复制为文件名 sudo dpkg -i xxx.deb2. 为VSCode换皮肤 3. 下载SSH插件和Docker插件 4. 配置SSH 把密钥key文件放在/home/your_user_name/.ssh/里面&#xff0c;然后在/home/your_user_name/.ssh/c…

第1集《修习止观坐禅法要》

《修习止观坐禅法要》诸位法师&#xff0c;诸位学员&#xff0c;阿弥院佛&#xff01; 我们今天能够暂时放下世间的尘劳&#xff0c;大家在一起研究佛法的课程&#xff0c;这件事情在我们的生命当中是非常的稀有难得。 基本上&#xff0c;我们佛法的修习目的是追求身心的安乐…

基于vue的3D高德地图的引入

在引入高德地图的时候需要先注册一个账号 登录下面的网站 账号认证 | 高德控制台 (amap.com) 打开首页应用管理&#xff0c;我的应用 创建新的应用 根据自己的需求进行选择 创建完成之后&#xff0c;点击添加key 不同的服务平台对应不同的可使用服务&#xff0c;选择自己适…

3.js - 模板渲染 - 金属切面效果

md&#xff0c;狗不学&#xff0c;我学 源码 // ts-nocheck// 引入three.js import * as THREE from three// 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls// 导入lil.gui import { GUI } from three/examples/jsm/libs/lil-gui.m…

机器学习与深度学习:区别(含工作站硬件推荐)

一、机器学习与深度学习区别 机器学习&#xff08;ML&#xff1a;Machine Learning&#xff09;与深度学习&#xff08;DL&#xff1a;Deep Learning&#xff09;是人工智能&#xff08;AI&#xff09;领域内两个重要但不同的技术。它们在定义、数据依赖性以及硬件依赖性等方面…

如何在忘记密码的情况下解锁Android手机?

您的 Android 设备密码有助于保护您的数据并防止您的个人信息被滥用。但是&#xff0c;如果您被锁定在Android设备之外怎么办&#xff1f;我们知道忘记您的 Android 手机密码是多么令人沮丧&#xff0c;因为它会导致您的设备和数据无法访问。在本技术指南中&#xff0c;我们将向…

[图解]企业应用架构模式2024新译本讲解23-标识映射2

1 00:00:00,950 --> 00:00:02,890 好&#xff0c;我们往下走 2 00:00:04,140 --> 00:00:04,650 一样的 3 00:00:04,660 --> 00:00:07,170 这前面也见过了&#xff0c;定义一个对象数组 4 00:00:07,870 --> 00:00:12,820 数组的长度就是字段的数量&#xff0c;4个…

学IT上培训班真的有用吗?

在学习IT技术的过程中&#xff0c;你是否也被安利过各种五花八门的技术培训班&#xff1f;这些培训班都是怎样向你宣传的&#xff0c;你又对此抱有着怎样的态度呢&#xff1f;在培训班里学技术&#xff0c;真的有用吗&#xff1f; 一、引入话题 IT行业是一个快速发展和不断变化…

概率统计(二)

二维离散型 联合分布律 样本总数为16是因为&#xff0c;两封信分别可以放在4个信箱 边缘分布律 条件分布律 独立性 选填才能用秒杀 联合概率乘积不等于边缘概率的乘积则不独立 二维连续型 区间用一重积分面积用二重积分 离散型随机变量

Python题解Leetcode Hot100之二叉树

1. 二叉树的中序遍历 题目描述 给定一个二叉树&#xff0c;返回它的中序遍历。解题思路 使用递归的方法对左子树进行中序遍历&#xff0c;然后访问根节点&#xff0c;最后对右子树进行中序遍历。也可以使用栈来模拟递归的过程&#xff0c;迭代地进行中序遍历。代码class Solut…

医院挂号系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;患者管理&#xff0c;医生管理&#xff0c;专家信息管理&#xff0c;科室管理&#xff0c;预约信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;专家信息&#xff0…

Java入门-异常机制

java异常机制 异常概念 在Java中&#xff0c;异常处理(exception handling) : java语言或者程序员开发提供的一种机制&#xff0c;当有不正常的情况发生时&#xff0c;可以发出信号。这种发出信号的过程被称为抛出异常(throwing an exception)。 java异常体系 Error Error类对…

数据库SQL Server常用字符串函数

文章目录 字符串函数 字符串函数 CONCAT:拼接字符串 CONCAT(COLUMN1,_,COLUMN2) AS COLCONVERT&#xff1a;转换数据类型 CONVERT(data_type(length),data_to_be_converted,style)例如&#xff1a;CONVERT(VARCHAR(10),GETDATE(),110) SUBSTRING()&#xff1a;从字符串中返回…

24.6.30

星期一&#xff1a; 补cf global round26 D cf传送门 思路&#xff1a;把s中非a字符存下来&#xff0c;共m个&#xff0c;然后暴力检测&#xff0c;复杂度有点迷 代码如下&#xff1a; ll n;void solve(){string s; cin &…

硬件开发笔记(二十四):贴片电容的类别、封装介绍,AD21导入贴片电容、原理图和封装库3D模型

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140241817 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

(南京观海微电子)——电阻应用及选取

什么是电阻&#xff1f; 电阻是描述导体导电性能的物理量&#xff0c;用R表示。 电阻由导体两端的电压U与通过导体的电流I的比值来定义&#xff0c;即&#xff1a; 所以&#xff0c;当导体两端的电压一定时&#xff0c;电阻愈大&#xff0c;通过的电流就愈小&#xff1b;反之&…

Java+MySQL8.0.36+ElementUI数字化产科信息管理系统之”五色管理”

JavaMySQL8.0.36ElementUI数字化产科信息管理系统之”五色管理” 一、数字化产科信息管理系统概述 数字化产科信息管理五色管理是一种基于孕产妇妊娠风险的分类管理方法&#xff0c;通过数字化手段实现孕产妇全周期的健康风险评估与管理。该方法将孕产妇按照风险等级分为绿色、…

【HTML入门】第三课 - 标题、段落、空格

这一小节&#xff0c;我们说一些比较零散的知识&#xff0c;HTML课程中呢&#xff0c;其实就是一些标签&#xff0c;正是这些标签组成了前端网页的各种元素&#xff0c;所以你也可以叫他们标签元素。 像前两节我们说的&#xff0c;html head body title meta style 。这些都是…