Redis源码阅读--adlist(10)

双端链表 adlist.c .h
Redis里的List是双端链表的形式

typedef struct listNode {// 前置节点 struct listNode *prev; // 后置节点 struct listNode *next; // 节点的值 void *value; } listNode;

Redis源码阅读--adlist(10)
文章图片

/* * 双端链表结构 */ 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;

Redis源码阅读--adlist(10)
文章图片

/* * 双端链表迭代器 */ typedef struct listIter {// 当前迭代到的节点 listNode *next; // 迭代的方向 int direction; } listIter; /* Directions for iterators * * 迭代器进行迭代的方向 */ // 从表头向表尾进行迭代 #define AL_START_HEAD 0 // 从表尾到表头进行迭代 #define AL_START_TAIL 1

注意
  1. 这里的表头和表尾的next都是指向null的所以永远无环
  2. 链表节点是使用的void*指针来保存节点值的 所以链表可以保存各种不同类型的值
void指针可以指向任意类型的数据,就是说可以用任意类型的指针对void指针赋值
int *a; void *p p=a;

#include using namespace std; int main() {int b[] = { 1,2 }; int* a = b; void *c; c = a; cout << c<

这里你是可以输出c的 c存的就是指针a所村的 也就是 b数组的内存地址,但是你是不能*c 因为没有类型void
API 指定位置插入
/* * 创建一个包含值 value 的新节点,并将它插入到 old_node 的之前或之后 * * 如果 after 为 0 ,将新节点插入到 old_node 之前。 * 如果 after 为 1 ,将新节点插入到 old_node 之后。 * * T = O(1) */ list *listInsertNode(list *list, listNode *old_node, void *value, int after) { listNode *node; // 创建新节点 if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; // 保存值 node->value = https://www.it610.com/article/value; // 将新节点添加到给定节点之后 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; } }// 更新新节点的前置指针 if (node->prev != NULL) { node->prev->next = node; } // 更新新节点的后置指针 if (node->next != NULL) { node->next->prev = node; }// 更新链表节点数 list->len++; return list; }

迭代器
/* * 为给定链表创建一个迭代器, * 之后每次对这个迭代器调用 listNext 都返回被迭代到的链表节点 * * direction 参数决定了迭代器的迭代方向: *AL_START_HEAD :从表头向表尾迭代 *AL_START_TAIL :从表尾想表头迭代 * * T = O(1) */ listIter *listGetIterator(list *list, int direction) { // 为迭代器分配内存 listIter *iter; if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL; // 根据迭代方向,设置迭代器的起始节点 if (direction == AL_START_HEAD) iter->next = list->head; else iter->next = list->tail; // 记录迭代方向 iter->direction = direction; return iter; }

【Redis源码阅读--adlist(10)】查找
/* * 查找链表 list 中值和 key 匹配的节点。 * * 对比操作由链表的 match 函数负责进行, * 如果没有设置 match 函数, * 那么直接通过对比值的指针来决定是否匹配。 * * 如果匹配成功,那么第一个匹配的节点会被返回。 * 如果没有匹配任何节点,那么返回 NULL 。 * * T = O(N) */ listNode *listSearchKey(list *list, void *key) { listIter *iter; listNode *node; // 迭代整个链表 iter = listGetIterator(list, AL_START_HEAD); while((node = listNext(iter)) != NULL) {// 对比 if (list->match) { if (list->match(node->value, key)) { listReleaseIterator(iter); // 找到 return node; } } else { if (key == node->value) { listReleaseIterator(iter); // 找到 return node; } } }listReleaseIterator(iter); // 未找到 return NULL; }

    推荐阅读