1. 简介
链表在Redis中使用广,包括列表键的事件、客户端的状态保存等都使用了链表。
2. 实现
2.1 链表节点
adlist.h/listNode
结构来表示链表节点:
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
其实也就是我们平常数据结构中的双向链表节点的定义。
2.2 链表
adlist.h/list
结构来表示链表:
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;
需要注意一下几点:
- 双端:带有head和tail指针,指向头尾的复杂度都是O(1);
- 无环:表头节点的prev指针和表尾节点的nex指针指向NULL,因此它并不是一个环形链表;
- 带表头和表尾指针;
- 有链表长度计数器;
- 多态:链表节点的value使用void*指针来保存,因此它可以用于保存各种不同类型的值。它们通过提供的dup、free、match三个特定函数来完成对不同类型对的操作。
链表结构就是这么简单。需要注意的是,Redis里的列表键并不都是使用链表来实现的。当元素比较多,或者列表中包含的元素都是比较长的字符串时,Redis就会使用链表来作为列表键的底层实现。压缩列表(ziplist)是另一种列表键的实现方案。