最新redis底层数据结构之双向链表

本文详细介绍了Redis中作为List底层数据结构的双向链表,涵盖了链表的设计、性能优化,如双向指针、头尾指针和长度属性。同时,文章分析了链表的源码,包括创建、清空、释放、节点操作等API,为读者提供深入理解。
摘要由CSDN通过智能技术生成

一)简介

        双向链表是redis中数据类型List的底层数据结构之一,双向链表也是一种常见的数据结构,在redis中也是大同小异 主要包括三个元素分别为链表,节点,链表迭代器,其设计比较简单 api易懂 为了方便大家阅读 本文做了详细的源码介绍 ,可以收藏下来。


二)性能优化分析

  • 节点的双向指针prev和next,方便通过迭代器从头至尾或从尾至头遍历。
  • 链表的头尾指针head和tail,对链表的头尾插入,以及头尾节点读取,高效地实现list的一些指令(如push 和pop相关指令)。
  • 链表的长度len,得计算链表长度的时间复杂度为O(1),不需要遍历整个链表。

三)来源

        以下源码均来自redis 6.0.12版本的 adlist.h和adlist.c文件。


四)数据结构类型定义

/* 双向链表中的节点 */
typedef struct listNode {
   
    struct listNode *prev;//前驱指针 *后面简称前指针
    struct listNode *next;//后继指针 *后面简称后指针
    void *value;//节点值
} listNode;

/* 双向链表的迭代器 */
typedef struct listIter {
   
    listNode *next;//下一个节点
    int direction;//迭代方向
} listIter;

/* 双向链表 */
typedef struct list {
   
    listNode *head;// 链表头节点
    listNode *tail;// 链表尾节点
        // 定义三个函数指针  为什么要定义这三个函数指针?因为listnode中的数据区域为一个void类型的指针(类似java中泛型),
        //所指向的结构可能千差万别,而且这些内存需要手动释放。将常用的这几个函数定义在这里,可以在需要的时候直接回调。
    
    void *(*dup)(void *ptr);//复制节点值
    void (*free)(void *ptr);//释放节点值
    int (*match)(void *ptr, void *key);///匹配节点值是否相等
    unsigned long len;    // 链表长度
} list;


五)宏定义

宏名称 作用
listLength 获取链表的长度值
listFirst 获取链表的首指针
listLast 获取链表的尾指针
listPrevNode 获取当前节点的前驱节点指针
listNextNode 获取当前节点的后继节点指针
listNodeValue 获取当前节点所存储的值
listSetDupMethod 设置链表节点value的复制函数
listSetFreeMethod 设置链表节点value的释放内存函数
listSetMatchMethod 设置链表节点value的比较函数
listGetDupMethod 获取链表节点value的复制函数
listGetFree 获取链表节点value的释放内存函数
listGetMatchMethod 获取链表节点value的比较函数


六)API简介

函数 参数 定义 复杂度
list *listCreate(void); 创建一个list O(1)
void listEmpty(list *list); 要清空元素的链表 在不破坏链表本身的情况下,从链表中删除所有元素 O(N)
void listRelease(list *list); 要释放的链表 释放链表,清空链表然后释放链表本身的空间 O(N)
list *listAddNodeHead(list *list, void *value); 链表,添加节点的值 再链表头部添加一个节点 O(1)
list *listAddNodeTail(list *list, void *value); 链表,添加节点的值 再链表尾部添加一个节点 O(1)
list *listInsertNode(list *list, listNode *old_node, void *value, int after); 链表,指定节点,添加节点的值,前或者后 在链表的指定节点前或者后添加一个节点 O(1)
void listDelNode(list *list,listNode *node); 链表,指定节点 删除指定的节点 O(1)
listIter *listGetIterator(list *list, int direction); 链表,迭代方向 生成双向链表的迭代器 O(1)
void listReleaseIterator(listIter *iter); 指定迭代器 释放双向链表的迭代器 O(1)
listNode *listNext(listIter *iter); 指定迭代器 通过迭代器获取下一个节点 O(1)
list *listDup(list *orig); 要被复制的链表 创建指定链表的副本 O(N)
listNode *listSearchKey(list *list, void *key); 链表,指定的值 查找与指定key相同值的节点 O(N)
listNode *listIndex(list *list, long index); 链表,索引值 根据给定的索引值,返回相应的节点 O(N)
void listRewind(list *list, listIter *li); 链表,迭代器 重新初始化迭代器,迭代方向从头至尾 O(1)
void listRewindTail(list *list, listIter *li); 链表,迭代器 重新初始化迭代器,迭代方向从尾至头 O(1)
void listRotateTailToHead(list *list); 链表 将链表的尾节点移到链表的头节点 O(1)
void listRotateHeadToTail(list *list); 链表 将链表的头节点移到链表的尾节点 O(1)
void listJoin(list *l,list *o); 合并链表,被合并链表将两个链表合并o链表合并到l链表后面 O(1)


七)API源码分析


    listCreate

//创建一个新链表。创建的链表可以使用listRelease()释放,但是每个节点的私有值需要用户在调用listRelease()之前释放,或者使用listSetFreeMethod设置一个free方法。出现错误时,返回NULL。否则指向新列表的指针。
list *listCreate(void)
{
   
    struct list *list;

    if ((list = zmalloc(sizeof(*list))) == NULL)
        return NULL;
    //设置新列表的默认值
    list->head = list->tail = NULL;
    list->len = 0;
    list->dup = NULL;
    list->free = NULL;
    list->match = NULL;
    return list;
}
//创建一个新链表。

    listEmpty

/* 在不破坏链表本身的情况下,从链表中删除所有元素. */
void listEmpty(list *list)
{
   
    unsigned long len;
    listNode *current, *next;

    current = list->head;
    len = list->len;
    while(len--
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值