一、双向链表简介 双向链表作为一种常见的数据结构,在严蔚敏数据结构书里有详细的讲解,双向链表的每个数据节点都有两个指针,分别指向后继与前驱节点,因此从双向链表中的任意一个节点开始都可以很方便地访问其前驱与后继节点。 二、Redis中双向链表数据结
一、双向链表简介
双向链表作为一种常见的数据结构,在严蔚敏数据结构书里有详细的讲解,双向链表的每个数据节点都有两个指针,分别指向后继与前驱节点,因此从双向链表中的任意一个节点开始都可以很方便地访问其前驱与后继节点。
二、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源码方面的帮助。
本文原创发布php中文网,转载请注明出处,感谢您的尊重!