Redis内部数据结构详解之双向链表(linkedlist)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Acceptedxukai/article/details/17467373

本文所引用的源码全部来自Redis2.8.2版本。

Redis中linkedlist数据结构与API相关文件是adlist.c, adlist.h。

本文主要讲解Redis中对双向链表的详细实现,以及相关API的分析,对于双向链表本身可以从任意一本数据结构书本中得到详解。

转载请注明,来自:http://blog.csdn.net/acceptedxukai/article/details/17467373

一、双向链表简介

双向链表作为一种常见的数据结构,在严蔚敏数据结构书里有详细的讲解,双向链表的每个数据节点都有两个指针,分别指向后继与前驱节点,因此从双向链表中的任意一个节点开始都可以很方便地访问其前驱与后继节点。

二、Redis中双向链表数据结构以及相关宏定义

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;//链表尾
    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的比较函数

三、Redis中双向链表API介绍

名称

作用

复杂度

listCreate

创建一个新双向链表

O(1)

listRelease

释放一个双向链表以及包含的节点内存

O(N)

listAddNodeHead

将一个节点添加到链表的表头

O(1)

listAddNodeTail

将一个节点添加到链表的表尾

O(1)

listInsertNode

将一个节点添加到给定节点的之后或之前

O(1)

listDelNode

删除给定的节点

O(1)

listGetIterator

生成双向链表的迭代器

O(1)

listReleaseIterator

释放双向链表的迭代器

O(1)

listNext

通过迭代器获取下一个节点

O(1)

listDup

创建给定链表的副本

O(N)

listSearchKey

查找与给定key相同值的节点

O(N)

listIndex

根据给定的索引值,返回相应的节点

O(N)

listRewind

重新初始化迭代器,迭代方向从头至尾

O(1)

listRewindTail

重新初始化迭代器,迭代方向从尾至头

O(1)

listRotate

取出链表尾节点并插入到头部

O(1)

四、Redis双向链表性能分析

Redis中的双向链表也许是Redis中最简单最容易实现的数据结构,对于API就不多说了,都很简单,也没啥可以说的,下面简单分析一下双向链表的性能。

listNode拥有prev前驱指针和next后继指针,因此通过迭代器可以很方便的对链表从从头至尾或从尾至头遍历;

list拥有header头指针和tail为指针,对于在链表的头部或尾部进行插入节点的时间复杂度全部为O(1),高效地实现了Redis中一些指令的操作;

list自带保存链表长度的字段len,使得计算链表长度的时间复杂度为O(1)。

五、小结

双向链表主要有两个作用:作为Redis列表数据类型的底层实现方法之一;作为通用数据结构可以被其他功能模块使用。

双向链表实现简单,Redis对双向链表加以改造,添加保存节点长度的字段,以及实现自己的迭代指针,使得一些数据操作变得简单。

最后感谢黄健宏(huangz1990)的Redis设计与实现及其他对Redis2.6源码的相关注释对我在研究Redis2.8源码方面的帮助。



猜你喜欢

转载自blog.csdn.net/Acceptedxukai/article/details/17467373