Redisbook学习笔记(1)双端链表

 

双端链表作为一种通用的数据结构在Redis 内部使用得非常多它既是Redis 列表结构的底
层实现之一还被大量Redis 模块所使用用于构建Redis 的其他功能。

对列表类型的键进行操作——比如执行
RPUSH 、LPOP 或LLEN 等命令时程序在底层操作的可能就是双端链表。

wKiom1LSmVTieEL_AAD1MIhqxfA159.jpg

 

Note: Redis 列表使用两种数据结构作为底层实现
1. 双端链表
2. 压缩列表
因为双端链表占用的内存比压缩列表要多所以当创建新的列表键时列表会优先考虑使用压
缩列表作为底层实现并且在有需要的时候才从压缩列表实现转换到双端链表实现。

 

除了实现列表类型以外双端链表还被很多Redis 内部模块所应用
. 事务模块使用双端链表来按顺序保存输入的命令
. 服务器模块使用双端链表来保存多个客户端
. 订阅/发送模块使用双端链表来保存订阅模式的多个客户端
. 事件模块使用双端链表来保存时间事件time event


类似的应用还有很多在后续的章节中我们将看到双端链表在Redis 中发挥着重要的作用。

双端链表的实现由listNode 和list 两个数据结构构成下图展示了由这两个结构组成的一
个双端链表实例

wKioL1LSmovClwQJAAB_unCATkw239.jpg

 

其中listNode 是双端链表的节点

typedef struct listNode {
// 前驱节点
struct listNode *prev;
// 后继节点
struct listNode *next;
// 值
void *value;
} listNode;

而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;

 

注意listNode 的value 属性的类型是void * 说明这个双端链表对节点所保存的值的类型
不做限制。
对于不同类型的值有时候需要不同的函数来处理这些值因此list 类型保留了三个函数指针——dup 、free 和match 分别用于处理值的复制、释放和对比匹配。在对节点的值进行处
理时如果有给定这些函数那么它们就会被调用。

 

另外从这两个数据结构的定义上也可以它们的一些行为和性能特征


1、 listNode 带有prev 和next 两个指针因此对链表的遍历可以在两个方向上进行从
表头到表尾或者从表尾到表头。


2、list 保存了head 和tail 两个指针因此对链表的表头和表尾进行插入的复杂度都为O(1) ——这是高效实现LPUSH 、RPOP 、RPOPLPUSH 等命令的关键。


3、list 带有保存节点数量的len 属性所以计算链表长度的复杂度仅为O(1) 这也保证
了LLEN 命令不会成为性能瓶颈。

 

Redis 为双端链表实现了一个迭代器这个迭代器可以从两个方向对双端链表进行迭代
1、沿着节点的next 指针前进从表头向表尾迭代
2、沿着节点的prev 指针前进从表尾向表头迭代


以下是迭代器的数据结构定义

typedef struct listIter {
// 下一节点
listNode *next;
// 迭代方向
int direction;
} listIter;

 

direction 记录迭代应该从那里开始
1、 如果值为adlist.h/AL_START_HEAD 那么迭代器执行从表头到表尾的迭代
2、 如果值为adlist.h/AL_START_TAIL 那么迭代器执行从表尾到表头的迭代

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值