首页 > 数据库 >【Redis】Redis数据结构——链表

【Redis】Redis数据结构——链表

时间:2023-04-29 11:04:02浏览次数:33  
标签:listNode list Redis 链表 数据结构 节点 指针


【Redis】Redis数据结构——链表

注意事项:

本文第三点redis中操作列表的相关命令可参考博文:

【Redis】Redis基础命令集详解_Etui۹(・༥・´)و ̑̑的博客

本文参考内容如下:

1、Redis数据结构——链表 - 随心所于 -

2、《Redis设计与实现》(黄健宏·著)第3章 链表

本文仅供学习交流使用!

1、Redis中的链表

链表在Redis中的应用非常广泛,列表键的底层实现之一就是链表。当一个列表包含了数量较多的元素,又或者列表中包含的元素为较长的字符串,Redis就会使用链表作为列表键的底层实现。

例如, 以下展示的 integers 列表键包含了从 11024 共一千零二十四个整数:

redis> LLEN integers
(integer) 1024

redis> LRANGE integers 0 10
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
9) "9"
10) "10"
11) "11"

integers 列表键的底层实现就是一个链表, 链表中的每个节点都保存了一个整数值。

2、链表与链表节点的实现

每个链表节点使用一个 listNode 结构来表示:

typedef struct listNode {

    // 前置节点
    struct listNode *prev;

    // 后置节点
    struct listNode *next;

    // 节点的值
    void *value;

} listNode;

多个 listNode 可以通过 prevnext 指针组成双端链表, 如图 所示。

【Redis】Redis数据结构——链表_底层实现

虽然仅仅使用多个 listNode 结构就可以组成链表, 但使用 adlist.h/list 来持有链表的话, 操作起来会更方便:

typedef struct list {

    // 表头节点
    listNode *head;

    // 表尾节点
    listNode *tail;

    // 链表所包含的节点数量
    unsigned long len;

    // 节点值复制函数
    void *(*dup)(void *ptr);

    // 节点值释放函数
    void (*free)(void *ptr);

    // 节点值对比函数
    int (*match)(void *ptr, void *key);

} list;

list 结构为链表提供了表头指针 head 、表尾指针 tail , 以及链表长度计数器 len , 而 dupfreematch 成员则是用于实现多态链表所需的类型特定函数:

  • dup 函数用于复制链表节点所保存的值;
  • free 函数用于释放链表节点所保存的值;
  • match 函数则用于对比链表节点所保存的值和另一个输入值是否相等。

下图是由一个 list 结构和三个 listNode 结构组成的链表:

【Redis】Redis数据结构——链表_Redis_02

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

  • 双向: 链表节点带有 prevnext 指针, 获取某个节点的前置节点和后置节点的复杂度都是 O(1) 。
  • 无环: 表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL , 对链表的访问以 NULL 为终点。
  • 带表头指针和表尾指针: 通过 list 结构的 head 指针和 tail 指针, 程序获取链表的表头节点和表尾节点的复杂度为 O(1) 。
  • 带链表长度计数器: 程序使用 list 结构的 len 属性来对 list 持有的链表节点进行计数, 程序获取链表中节点数量的复杂度为 O(1) 。
  • 多态: 链表节点使用 void* 指针来保存节点值, 并且可以通过 list 结构的 dupfreematch 三个属性为节点值设置类型特定函数, 所以链表可以用于保存各种不同类型的值。

3、数组、单链表以及双向无环链表时间复杂度对比

操作\时间复杂度

数组

单链表

双向链表

rpush(从右边添加元素)

O(1)

O(1)

O(1)

lpush(从左边添加元素)

0(N)

O(1)

O(1)

lpop (从右边删除元素)

O(1)

O(1)

O(1)

rpop (从左边删除元素)

O(N)

O(1)

O(1)

lindex(获取指定索引下标的元素)

O(1)

O(N)

O(N)

len (获取长度)

O(N)

O(N)

O(1)

linsert(向某个元素前或后插入元素)

O(N)

O(N)

O(1)

lrem (删除指定元素)

O(N)

O(N)

O(N)

lset (修改指定索引下标元素)

O(N)

O(N)

O(N)

我们可以看到在列表对象常用的操作中双向链表的优势所在。但双向链表因为使用两个额外的空间存储前驱和后继指针,因此在数据量较小的情况下会造成空间上的浪费(因为数据量小的时候速度上的差别不大,但空间上的差别很大)。这是一个时间换空间还是空间换时间的思想问题,Redis在列表对象中小数据量的时候使用压缩列表作为底层实现,而大数据量的时候才会使用双向无环链表。

4、重点

  • 链表被广泛用于实现 Redis 的各种功能, 比如列表键, 发布与订阅, 慢查询, 监视器, 等等。
  • 每个链表节点由一个 listNode 结构来表示, 每个节点都有一个指向前置节点和后置节点的指针, 所以 Redis 的链表实现是双端链表。
  • 每个链表使用一个 list 结构来表示, 这个结构带有表头节点指针、表尾节点指针、以及链表长度等信息。
  • 因为链表表头节点的前置节点和表尾节点的后置节点都指向 NULL , 所以 Redis 的链表实现是无环链表。
  • 通过为链表设置不同的类型特定函数, Redis 的链表可以用于保存各种不同类型的值。

本文仅供学习参考!


标签:listNode,list,Redis,链表,数据结构,节点,指针
From: https://blog.51cto.com/u_14210396/6236654

相关文章

  • 云LIS系统基于ASP.NET CORE 3.1 MVC + SQLserver + Redis技术实践
    云LIS   利用云LIS实现区域内各级医院门诊、住院等日常医疗业务和行政业务的全流程管理和医院的无纸化运营,规范就医流程,提升医疗质量,提供科学决策支持,增强患者的就医体验。云LIS是为区域医疗提供临床实验室信息服务的计算机应用程序,可协助区域内所有临床实验室相互协调并......
  • 【教程分享】一键部署Redis,轻松搞定Docker安装和配置!
    1下载下载6.2.7版本:[root@service-monitoring~]#dockerpullredis:6.2.76.2.7:Pullingfromlibrary/redis025c56f98b67:Pullcomplete060e65aed679:Pullcompleteb95291e865b7:Pullcompletee3023c0b11d1:Pullcomplete143500497a02:Pullcompletec38298c......
  • 《大话数据结构》读书笔记 附PDF #C3
    刚刚读完了《大话数据结构》,这本书真的是一本不错的入门级别的数据结构和算法的教材。首先,作者通过幽默的语言和丰富的图示,使得枯燥的数据结构与算法变得生动有趣。在阅读过程中,我感受到了作者对于知识点深入浅出的讲解,即使是像我这样初学者也能够轻松理解。其次,书中的配套练习......
  • Redis高可用方案汇总
    我们在项目中使用redis,肯定不会是单点部署Redis服务的。因为单点部署一旦宕机,就不可用了。为了实现高可用,通常的做法是,将数据库复制多个副本以部署在不同的服务器上,其中一台挂了也可以继续提供服务。Redis实现高可用有三种部署模式:主从模式,哨兵模式,集群模式。1.主从模式主从模式......
  • java设计单链表
    packagelinked;/***@date2023/4/2622:51*@description单链表*/publicclassSingleLinkedList{privateintsize=0;privateNodehead;privateNodetail;publicstaticclassNode{privateObjectdata;privateNodenext;......
  • Redis WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/s
    RedisWARNING:TheTCPbacklogsettingof511cannotbeenforcedbecause/proc/sys/net/core/somaxconnissettothelowervalueof128. 内核参数默认128,对于负载很大的服务是不够的。改为2048或者更大echo2048> /proc/sys/net/core/somaxconn  系统重启后失效v......
  • 银河麒麟V10系统安装Redis
    原文链接:https://www.cnblogs.com/liunaixu/p/17138335.html一、准备工作安装环境:银河麒麟KylinV101、Redis是基于C语言编写的,因此首先需要安装Redis所需要的gcc依赖:[root@localhostopt]#yuminstallcpp输入:y 2、[root@localhostopt]#yuminstallbinutils 3、[......
  • 词库过大导致的Redis超时问题-RedisCommandTimeoutException
    问题Redis缓存超时问题报错内容redisio.lettuce.core.RedisCommandTimeoutException:Commandtimedoutafter10second(s)原因1.报错原因这里是因为词库的数据量过大,在开发库中有40w的数据需要刷到缓存中,因数据量过大时间久,Redis直接刷挂了2.为什么线上没有问题线上的......
  • 两个链表的第一个公共结点
    使用空间存储节点的解法classSolution{public:set<ListNode*>s;ListNode*findFirstCommonNode(ListNode*headA,ListNode*headB){for(autoi=headA;i;i=i->next)s.insert(i);for(autoi=headB;i;i=i->next)......
  • Redis客户端
    https://www.jianshu.com/p/b5617c901fb7 使用telnet连接redis ......