【Redis】 链表

Metadata

title: 【Redis】 链表
date: 2023-07-09 08:30
tags:
  - 行动阶段/完成
  - 主题场景/数据存储
  - 笔记空间/KnowladgeSpace/ProgramSpace/BasicsSpace
  - 细化主题/数据存储/Redis
categories:
  - 数据存储
keywords:
  - 数据存储/Redis
description: 【Redis】 链表

概述

当一个列表键包含了数量比较多的元素,或者列表中包含的元素都是比较长的字符串时,Redis 就会使用链表作为列表键的底层实现。

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

链表和链表节点的实现

typedef struct listNode{
    //前置节点
    struct listNode *prev;
    //后置节点
    struct listNode *next;
    //节点的值
    void *value;
}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;

整个链表串起来后,如下图:

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

双端:链表节点带有 prev 和 next 指针,获取前置和后置节点的复杂度都是 O(1)。
无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问以 NULL 为终点。 带表头指针和表尾指针 带链表长度计数器 。
头尾指针:将程序获取头尾节点的复杂度降为 O(1)。
长度计数器:将程序获取表长的复杂度降为 O(1)。
多态:链表节点使用 void * 指针来保存节点值,并且可以通过 list 结构的dup、free、match为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值。

链表时间复杂度

链表相关操作及时间复杂度:

操作 时间复杂度
返回链表长度/头尾节点/给定节点的前驱后继 O(1)
插入新节点到表尾/表头 O(1)
删除/查找给定节点 “0(N),N为链表长度”
拷贝/释放一个链表 “0(N),N为链表长度”

链表 API

函数 作用 时间复杂度
listSetDupMethod “将给定的函数设置为链表的节点值复制函数,复制函数可以通过链表的dup 属性直接获得” 0(1)
listGetDupMethod “返回链表当前正在使用的节点值复制函数” 0(1)
listSetFreeMethod “将给定的函数设置为链表的节点值释放函数,释放函数可以通过链表的 free 属性直接获得” 0(1)
listGetFree “返回链表当前正在使用的节点值释放函数” 0(1)
listSetMatchMethod “将给定的函数设置为链表的节点值对比函数,对比函数可以通过链表的match 属性直接获得” O(1)
listGetMatchMethod “返回链表当前正在使用的节点值对比函数” 0(1)
listLength “返回链表的长度(包含了多少个节点),链表长度可以通过链表的 len 属性直接获得” 0(1)
listFirst “返回链表的表头节点,表头节点可以通过链表的 head 属性直接获得” O(1)
listLast “返回链表的表尾节点,表尾节点可以通过链表的 tail 属性直接获得” O(1)
listPrevNode “返回给定节点的前置节点,前置节点可以通过节点的prev 属性直接获得” 0(1)
listNextNode “返回给定节点的后置节点,后置节点可以通过节点的next 属性直接获得” 0(1)
listNodeValue “返回给定节点目前正在保存的值,节点值可以通过节点的value 属性直接获得” O(1)
listCreate “创建一个不包含任何节点的新链表” O(1)
listAddNodeHead 将一个包含给定值的新节点添加到给定链表 的表头 O(1)
listAddNodeTail 将一个包含给定值的新节点添加到给定链表 的表尾 0(1)
listInsertNode 将一个包含给定值的新节点添加到给定节点 的之前或者之后 0(1)
listSearchKey 查找并返回链表中包含给定值的节点 “O(N),N为链表长度”
listIndex 返回链表在给定索引上的节点 “O(M),N为链表长度”
listDelNode 从链表中删除给定节点 “O(M),N为链表长度”
listRotate “将链表的表尾节点弹出,然后将被弹出的节 点插人到链表的表头,成为新的表头节点” O(1)
listDup 复制一个给定链表的副本 “O(N),N为链表长度”
listRelease “释放给定链表,以及链表中的所有节点” “O(M),N为链表长度”