链表结点和链表结构
每个链表节点使用一个adlist.h/listNode结构来表示:
/*
* 链表节点
*/
typedef struct listNode {
// 前驱节点
struct listNode *prev;
// 后继节点
struct listNode *next;
// 值
void *value;
} listNode;
通过prev和next形成双向链表,通过链表来管理操作链表结点,也允许通过迭代器来访问链表
/*
* 链表
*/
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;
链表迭代器
typedef struct listIter {
// 下一节点
listNode *next;
// 迭代方向
int direction;
} listIter;
Redis链表的特性
- 双端:链表结点带有prev和next指针,获取某个结点的前置结点和后置结点的复杂度都是O(1)
- 无环: 表头节点的prev指针和表尾节点的next指针都指向NULL,对链表的访问以NULL为终点。
- 带链表长度计数器 程序获取链表中结点个数的复杂度为O(1)
- 多态,可以保存不同类型的值
源码特点
一些比较简单的工具函数如listLength,listFirst,listLast等,使用宏定义
/*
* 创建一个新列表
*
* 创建成功时返回列表,创建失败返回 NULL
*
* T = O(1)
*/
list *listCreate(void)
{
struct list *list;
// 为列表结构分配内存
if ((list = zmalloc(sizeof(*list))) == NULL)
return NULL;
// 初始化属性
list->head = list->tail = NULL;
list->len = 0;
list->dup = NULL;
list->free = NULL;
list->match = NULL;
return list;
}
/*
* 释放整个列表(以及列表包含的节点)
*
* T = O(N),N 为列表的长度
*/
void listRelease(list *list)
{
unsigned long len;
listNode *current, *next;
current = list->head;
len = list->len;
while(len--) {
next = current->next;
// 如果列表有自带的 free 方法,那么先对节点值调用它
if (list->free) list->free(current->value);
// 之后再释放节点
zfree(current);
current = next;
}
zfree(list);
}
/*
* 复制整个列表,成功返回列表的副本,内存不足而失败时返回 NULL 。
*
* 无论复制是成功或失败,输入列表都不会被修改。
*
* T = O(N),N 为 orig 列表的长度
*/
list *listDup(list *orig)
{
list *copy;
listIter *iter;
listNode *node;
if ((copy = listCreate()) == NULL)
return NULL;
// 复制属性
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match;
// 复制节点
iter = listGetIterator(orig, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
// 复制节点值
void *value;
if (copy->dup) {
value = copy->dup(node->value);
if (value == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
} else
value = node->value;
// 将新节点添加到新列表末尾
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
}
listReleaseIterator(iter);
return copy;
}