nbvf 发表于 2013-12-24 09:27:27

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

本文所引用的源码全部来自Redis2.8.2版本。
Redis中linkedlist数据结构与API相关文件是adlist.c, adlist.h。
本文主要讲解Redis中对双向链表的详细实现,以及相关API的分析,对于双向链表本身可以从任意一本数据结构书本中得到详解。

一、双向链表简介双向链表作为一种常见的数据结构,在严蔚敏数据结构书里有详细的讲解,双向链表的每个数据节点都有两个指针,分别指向后继与前驱节点,因此从双向链表中的任意一个节点开始都可以很方便地访问其前驱与后继节点。
二、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源码方面的帮助。

xcl9900 发表于 2013-12-24 09:27:33

只要有想见的人就不是孤身一人了

青野 发表于 2013-12-24 12:32:59

花.飞彼岸花.只为找到心爱德人.用黑暗来祭奠悲伤德残泪.花开花落.

水莹儿 发表于 2013-12-25 06:57:57

爱着的东西,真让人琢磨不清。

gdx 发表于 2013-12-25 16:07:37

*—–宝 贝、心 脏 旳(1/2)是 尓

youngfan007 发表于 2013-12-26 03:15:14

你让我四分五裂活得行尸走肉我就让你情火焚身死的干脆利落

宇文氏 发表于 2013-12-27 03:00:19

虽然我不知道前方的路会怎样,但我会加油的╰つ
页: [1]
查看完整版本: Redis内部数据结构详解之双向链表(linkedlist)