redis源码分析(3)链表adlist.c
adlist.c可以说是一个比较经典的双端链表,熟悉链表的话应该很快就能读懂。
数据结构都比较好懂。
/* Functions implemented as macros */ // 返回给定链表所包含的节点数量 // T = O(1) #define listLength(l) ((l)->len) // 返回给定链表的表头节点 // T = O(1) #define listFirst(l) ((l)->head) // 返回给定链表的表尾节点 // T = O(1) #define listLast(l) ((l)->tail) // 返回给定节点的前置节点 // T = O(1) #define listPrevNode(n) ((n)->prev) // 返回给定节点的后置节点 // T = O(1) #define listNextNode(n) ((n)->next) // 返回给定节点的值 // T = O(1) #define listNodeValue(n) ((n)->value) // 将链表 l 的值复制函数设置为 m // T = O(1) #define listSetDupMethod(l,m) ((l)->dup = (m)) // 将链表 l 的值释放函数设置为 m // T = O(1) #define listSetFreeMethod(l,m) ((l)->free = (m)) // 将链表的对比函数设置为 m // T = O(1) #define listSetMatchMethod(l,m) ((l)->match = (m)) // 返回给定链表的值复制函数 // T = O(1) #define listGetDupMethod(l) ((l)->dup) // 返回给定链表的值释放函数 // T = O(1) #define listGetFree(l) ((l)->free) // 返回给定链表的值对比函数 // T = O(1) #define listGetMatchMethod(l) ((l)->match)
创建一个新的链表:
/* * 创建一个新的链表 * * 创建成功返回链表,失败返回 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; }
释放链表:
头插
尾插
创建一个新的值为value的节点,插入到指定节点old_node之前或者之后。
/* * 创建一个包含值 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 = 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; }
删除指定节点
创建和释放迭代器:
重置迭代器的方向和起点:
返回迭代器当前指向的值,并使迭代器往指定方向移动一次。
复制一个链表:
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; }
寻找匹配的节点,并返回,如果没有找到返回NULL
返回链表在指定索引上的值
把尾节点移动到头部,成为新的表头节点。