做为一种经常使用数据结构,链表内置在不少高级编程语言里, 由于 C 语言没有内置这种数据结构, Redis 构建了本身的链表实现.git
链表在 Redis 中的应用十分普遍, 好比列表键的底层实现之一就是链表. 当一个列表键包含了数量较多的元素,或者列表中包含的元素都是比较长的字符串时, Redis 就会使用链表做为列表键的底层实现.
<!-- more -->
除了列表键以外, 发布与订阅、慢查询、监视器等功能也用到了链表.还有使用链表来构建客户端输出缓冲区等.github
对于链表的定义和相关算法,不少算法书籍已经作了详细的讲解.这里只对 Redis 中链表的实现作介绍.算法
每一个链表节点使用一个 listNode
结构来表示:编程
// file: adlist.h typedef struct listNode { struct listNode *prev; // 前置节点 struct listNode *next; //后置节点 void *value; //节点的值 } ListNode;
多个链表节点经过 prev
和 next
组成双端链表,
Redis 使用 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;
下图是由一个 lsit
结构和三个 ListNode
结构组成的链表.编程语言
Redis 的链表实现特性能够总结以下:函数
双端: 由于带有 prev
和 next
指针,获取某个节点的前置节点和后置节点的复杂度都是$O(1)$spa
无环: 表头的 prev
指针和表尾的 next
指针均指向 NULL
, 对链表的访问以 NULL
结束.指针
带表头指针和表尾指针: 经过 list
结构获取表头和表尾的复杂度为$ O(1)$.code
带链表长度计数器: list
结构的 len
属性对链表节点的长度计数, 获取链表中节点的数量复杂度为$ O(1)$
多态: 链表节点使用 void *
指针来保存节点值, 而且能够经过 list 结构的 dup
、free
、match
三个属性为节点值设置类型特定函数.链表能够用于保存各类不一样类型的值.
个人博客: http://ygmyth.github.io