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

Redis 的链表:像智能文件夹一样灵活的列表结构

目录

一、从传统数组的痛点到链表的优势​

二、链表的核心结构:文件夹与活页的组合​

2.1、 list 结构体:文件夹封面​

2.2、listNode 结构体:活页纸​

2.2.1、为什么用 void*?万能收纳袋的秘密​

2.2.2、多态带来的灵活性​

2.2.3、链表与 SDS 的完美配合​

1. 列表键名的存储​

2. 字符串类型节点的存储​

2.2.4、三大工具函数:链表的智能管家​

1. dup 函数:内容复印机​

2. free 函数:内容清理器​

3. match 函数:内容查找器​

三、Redis 链表的核心优势​

链表在 Redis 中的典型应用​

总结:链表与 SDS 的协同智慧​

如果说 SDS 是 Redis 的 "智能笔记本",那链表(list)就是把这些笔记本有序管理起来的 "智能文件夹系统"。当你执行lpush list 0 1 2 "hello" 'a'这样的命令时,Redis 就像在创建一个带多个口袋的文件夹,每个口袋里装着不同类型的笔记本。​

一、从传统数组的痛点到链表的优势​

想象你用两种方式整理文件:​

  • 传统数组像固定格子的抽屉:格子大小固定,想增减文件必须整个抽屉重建;要知道有多少文件得逐个清点;想在中间插入文件得挪动后面所有文件。​
  • Redis 链表像活页文件夹:可以随时增减页面,不用重建整个文件夹;封面标着文件总数;页面间用活页环连接,插入删除只需调整活页环。​

这就是为什么 Redis 列表(list)要采用链表结构 —— 它完美解决了动态数据管理的核心痛点。​

二、链表的核心结构:文件夹与活页的组合​

Redis 的链表结构由两个关键部分组成,就像文件夹系统的 "封面" 和 "活页":​

2.1、 list 结构体:文件夹封面​

struct list {​listNode *head; // 第一个活页(表头节点)​listNode *tail; // 最后一个活页(表尾节点)​unsigned long len; // 活页总数(节点数量)​void *(*dup)(void *ptr); // 复制工具(节点值复制函数)​void (*free)(void *ptr); // 销毁工具(节点值释放函数)​int (*match)(void *ptr,void *key); // 查找工具(节点值对比函数)​};​

这个结构体就像文件夹封面,记录着:​

  • 第一页和最后一页的位置(head 和 tail)​
  • 总共有多少页(len)​
  • 三套管理工具(复制、销毁、查找函数)​

2.2、listNode 结构体:活页纸​

struct listNode {​struct listNode *prev; // 前一页(前置节点)​struct listNode *next; // 后一页(后置节点)​void *value; // 页面内容(节点的值)​};​

每个节点就像一张活页纸:​

  • 左右两边的装订孔(prev 和 next)连接着前后页面​
  • 中间的内容区(value)可以放任何类型的内容​

2.2.1、为什么用 void*?万能收纳袋的秘密​

你可能会好奇,为什么 value 要用void*类型?这正是 Redis 链表的精妙之处 ——实现多态存储。​

  • 就像超市的购物袋(void*)可以装苹果、牛奶、纸巾等任何商品,不管它们是固体还是液体​
  • 就像 Java 的 Object 类能接收任何类型的对象,Redis 用void*让链表节点能存储任何类型的数据​
  • 当你存入数字 0 时,value 指向整数存储区;存入 "hello" 时,它指向 SDS 结构体​

2.2.2、多态带来的灵活性​

执行lpush list 0 1 2 "hello" 'a'后,链表会形成这样的结构:​

  • 第一个节点的 value 指向整数 0​
  • 第二个节点的 value 指向整数 1​
  • 第三个节点的 value 指向整数 2
  • 第四个节点的 value 指向 SDS 结构体(存储 "hello")​
  • 第五个节点的 value 指向 SDS 结构体(存储 "a")​

就像一个文件夹里既能放笔记本,又能放照片、名片,这种灵活性让 Redis 列表能适应各种场景。​

2.2.3、链表与 SDS 的完美配合​

SDS 在链表中扮演着双重角色,就像文件夹系统中的两种重要载体:​

1. 列表键名的存储​

列表名称 "list" 本身用 SDS 存储:​

len=4, free=4, buf=['l','i','s','t','\0']​

这就像文件夹封面上的标签,用 SDS 存储既方便修改名称,又能快速获取长度。​

2. 字符串类型节点的存储​

当节点值是字符串(如 "hello"、"a")时,这些值会用 SDS 存储,然后把 SDS 的指针交给 listNode 的 value:​

// "hello"节点的结构关系​

listNode.value →    sdshdr {​

                                        len=5,​

                                        free=5,​

                                        buf=['h','e','l','l','o','\0']​

                                }​

这种组合让链表同时拥有了:​

  • 链表的动态管理能力​
  • SDS 的字符串优化特性​

2.2.4、三大工具函数:链表的智能管家​

list 结构体中的三个函数指针就像文件夹的智能管理工具,处理不同类型内容时会自动适配:​

1. dup 函数:内容复印机​
  • 当复制整数节点时,它会创建新的整数副本​
  • 当复制 SDS 节点时,它会调用sdsdup函数复制整个字符串​
  • 类比:就像复印机知道复印照片用彩色模式,复印文档用黑白模式​
2. free 函数:内容清理器​
  • 释放整数节点时直接回收内存​
  • 释放 SDS 节点时会调用sdsfree函数,正确清理字符串空间​
  • 类比:就像垃圾桶知道纸类和塑料需要不同的处理方式​
3. match 函数:内容查找器​
  • 比较整数时直接对比数值​
  • 比较字符串时会调用sdslen和sdscmp等函数​
  • 类比:就像查找文件时,知道按文件名找文本,按尺寸找图片​

三、Redis 链表的核心优势​

特性​

生活比喻​

技术价值​

双向指针​

活页纸的前后连接​

支持 O (1) 时间复杂度的首尾操作​

len 属性​

文件夹的页数标记​

快速获取长度(O (1) 复杂度)​

void* value​

万能收纳袋​

支持多类型数据存储​

函数指针​

智能处理工具​

适配不同类型的操作需求​

与 SDS 结合​

专业载体 + 灵活管理​

兼顾字符串优化和动态管理​

链表在 Redis 中的典型应用​

  1. 消息队列:用lpush生产消息,rpop消费消息,链表的首尾操作效率极高​
  1. 最新列表:用lpush添加新元素,lrange获取最新 N 条,适合记录日志、动态​
  1. 分页查询:利用链表的有序性,通过lindex访问指定位置元素​

就像多功能文件夹既能做待办清单,又能做日记本,Redis 链表的灵活性让它成为许多场景的理想选择。​

总结:链表与 SDS 的协同智慧​

Redis 的链表设计体现了 "组合优于继承" 的设计哲学:​

  • 用链表解决动态管理问题​
  • 用 SDS 解决字符串存储问题​
  • 用 void * 和函数指针解决多态问题​

这种结构让 Redis 列表既能高效处理百万级数据,又能灵活支持各种数据类型,成为 Redis 五大基本数据结构中最灵活的成员之一。就像一套精心设计的文具系统,每个组件各有所长又完美配合,共同支撑起 Redis 的高性能表现。

http://www.dtcms.com/a/362313.html

相关文章:

  • 【题解 | 两种做法】洛谷 P4208 [JSOI2008] 最小生成树计数 [矩阵树/枚举]
  • FDTD_梯度波导学习(1)
  • 8.5 循环神经网络的从零开始实现
  • 二维元胞自动机:从生命游戏到自复制系统的计算宇宙
  • AI 安全与伦理:当大模型拥有 “决策能力”,我们该如何建立技术边界与监管框架?
  • Spring Cloud ------ Gateway
  • h5实现内嵌微信小程序支付宝 --截图保存海报分享功能
  • vmware中linux虚拟机提示磁盘空间不足
  • JavaScript 异步编程:Callback、Promise、async/await
  • 知识表示与处理1
  • 【光照】Unity中的[光照模型]概念辨析
  • 精确率、召回率、漏检率、误判率
  • 基于单片机倒车雷达/超声波测距设计
  • 《零基础入门AI:YOLOv3、YOLOv4详解》
  • React中纯 localStorage 与 Context + useReducer + localStorage对比
  • 【笔记】大模型训练(一)单卡训练的分析与优化策略
  • 微信小程序开发-day1
  • 一次诡异的报错排查:为什么时间戳变成了 ١٧٥٦٦٣٢٧٨
  • 9.1日IO作业
  • 大模型RAG项目实战:文本向量模型>Embedding模型、Reranker模型以及ColBERT模型
  • nCode 后处理常见问题汇总
  • 生成知识图谱与技能树的工具指南:PlantUML、Mermaid 和 D3.js
  • 过拟合 正则化(L1,L2,Dropout)
  • linux内核 - 文件系统相关的几个概念介绍
  • Ceres学习笔记
  • 从理论到RTL,实战实现高可靠ECC校验(附完整开源代码/脚本)(3) RTL实现实战
  • 智慧班牌系统基于Java+Vue技术栈构建,实现教育信息化综合管理。
  • ES6手录01-let与const
  • 2024 年 AI 技术全景图:大模型轻量化、多模态融合如何重塑产业边界?
  • c#:抽象类中的方法