redis中的adlist是一个简单的无环双向链表,主要逻辑在这两个文件中实现:
- adlist.h
- adlist.c
结构也很简单,数据结构中最基本的结构。
添加节点代码:
if (after) {
node->prev = old_node;
node->next = old_node->next;
if (list->tail == old_node) {
list->tail = node;
}
} else {
node->next = old_node;
node->prev = old_node->prev;
if (list->head == old_node) {
list->head = node;
}
}
after控制是在old_node前面添加还是在后面添加。
adlist中实现了一个简单的迭代器:
typedef struct listIter {
//指向迭代方向的下一个节点
listNode *next;
//迭代节点
int direction;
} listIter;
迭代器的一些方法:
//创建一个迭代器
listIter *listGetIterator(list *list, int direction);
//返回迭代器指向的节点并加一
listNode *listNext(listIter *iter);
void listReleaseIterator(listIter *iter);
//将迭代器指针指向头
void listRewind(list *list, listIter *li);
//将迭代器指针指向尾巴
void listRewindTail(list *list, listIter *li);
这样可以以如下代码来遍历整个链表:
listIter iter;
listNode *node;
listRewind(list, &iter);
while((node = listNext(&iter)) != NULL) {
......
}
因为链表结构是无环的,所以只需要判断prev或者next是不是NULL就知道有没有到两端,缺点是没法直接在中间某个节点重新遍历整个链表。
链表结构提供了dup方法用于对每个节点进行拷贝。如果用户没有提供这个方法,那就进行浅拷贝复制指针,否则进行用户自定义拷贝。
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;
}