redis链表的实现是双向链表.
每个链表节点的结构如下:
typedef struct listNode { //前置节点 struct listNode *prev; //后置节点 struct listNode *next; void *value; } listNode;
表头结构
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;
结构里面包含了迭代器,迭代器的结构
//迭代器 typedef struct listIter { listNode *next; int direction; //表明迭代方向 } listIter; #define AL_START_HEAD 0 //正向迭代器 #define AL_START_TAIL 1 //反向迭代器
将表头和节点结合起来,结构如图
adlist.c里定义了一些简单的对链表的操作,函数中如查找key,copy链表都是通过迭代器进行操作。
redis的链表实现特性:
- 双端:链表中有pre和next指针,获取某个节点的next节点或者pre节点的时间复杂度都是O(1);
- 无环:表头节点的pre和next都是指向null,对于链表的遍历都是以null结束;
- 带有表头指针和表尾指针:通过list结构的head和tail指针,获取list的表头节点和表尾节点的时间复杂度都是O(1);
- 带有长度计数器:list结构中有len属性,可以获取链表的长度,时间复杂度是O(1);
- 多态:链表节点使用void*指针来保存节点值,并且可以通过list结构的dup、free、match三个属性设置类型特定函数,所以链表可以用于保存各种不同类型的值。
链表被广泛用于实现Redis的各种功能,比如链表键、发布与订阅、慢查询、监视器等。