redis源码学习–数据结构之链表
redis中的链表介绍
redis中使用的是双向链表,定义在目录src\adlist.c中,结构体定义在同名的头文件中。
src\adlist.c封装了链表的API
在节点的基础上再封装了一层,定义了链表对象,除了指向链表首尾的指针,还声明了拷贝、清理内存和匹配的接口。这些接口都可以根据具体的链表具体定义。
// 节点的定义
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; //取值AL_START_HEAD等
} listIter;
下面介绍下拷贝链表操作来说明引入迭代器的便利:
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;
listRewind(orig, &iter); // 使用迭代器指向链表头
while((node = listNext(&iter)) != NULL) { // 检查是否到达链表尾
void *value;
if (copy->dup) {
value = copy->dup(node->value); // 使用自定义的拷贝函数拷贝节点内存
if (value == NULL) {
listRelease(copy);
return NULL;
}
} else
value = node->value;
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy);
return NULL;
}
}
return copy;
}
void listRewind(list *list, listIter *li) {
li->next = list->head;
li->direction = AL_START_HEAD;
}
listNode *listNext(listIter *iter)
{
listNode *current = iter->next;
if (current != NULL) {
if (iter->direction == AL_START_HEAD)
iter->next = current->next;
else
iter->next = current->prev;
}
return current;
}
总结:
- redis使用的是双向链表,表头结构声明了拷贝,释放,匹配三种方式,
- 引入了迭代器的定义,值得学习。