【redis源码分析】双向链表---adlist
来源:互联网 发布:淘宝宝贝展现量怎么看 编辑:程序博客网 时间:2024/06/05 05:40
双向链表的头文件定义:
#ifndef __ADLIST_H__#define __ADLIST_H__/* Node, List, and Iterator are the only data structures used currently. *//* * 双向链表节点 */typedef struct listNode { // 前驱节点 struct listNode *prev; // 后继节点 struct listNode *next; // 值 void *value;} listNode;/* * 链表迭代器 */typedef struct listIter { // 下一节点 listNode *next; // 迭代方向 int direction;} listIter;/* * 链表 */typedef struct list { // 表头指针 listNode *head; // 表尾指针 listNode *tail; // 节点数量 unsigned long len; // 复制函数,返回void的指针 void *(*dup)(void *ptr); // 释放函数,无返回值 void (*free)(void *ptr); // 比对函数,匹配成功返回1,不成功返回0 int (*match)(void *ptr, void *key);} list;/* Functions implemented as macros */// 返回链表的节点数量#define listLength(l) ((l)->len)// 返回链表的表头节点#define listFirst(l) ((l)->head)// 返回链表的表尾节点#define listLast(l) ((l)->tail)// 返回给定节点的前一个节点#define listPrevNode(n) ((n)->prev)// 返回给定节点的后一个节点#define listNextNode(n) ((n)->next)// 返回给定节点的值#define listNodeValue(n) ((n)->value)//设置链表的自定义函数#define listSetDupMethod(l,m) ((l)->dup = (m))#define listSetFreeMethod(l,m) ((l)->free = (m))#define listSetMatchMethod(l,m) ((l)->match = (m))//返回链表的自定义函数#define listGetDupMethod(l) ((l)->dup)#define listGetFree(l) ((l)->free)#define listGetMatchMethod(l) ((l)->match)/* Prototypes *///创建一个双向链表list *listCreate(void);//释放struct list结构void listRelease(list *list);//链表头插入节点list *listAddNodeHead(list *list, void *value);//链表尾插入节点list *listAddNodeTail(list *list, void *value);//在链表的指定节点前/后插入节点list *listInsertNode(list *list, listNode *old_node, void *value, int after);//删除链表的指定节点void listDelNode(list *list, listNode *node);//返回链表的迭代器listIter *listGetIterator(list *list, int direction);//取得当前迭代器的节点listNode *listNext(listIter *iter);//释放迭代器void listReleaseIterator(listIter *iter);//复制一个链表,返回新链表list *listDup(list *orig);//在链表中查找指定的节点value的节点,失败返回NULLlistNode *listSearchKey(list *list, void *key);//返回指定下标的节点,下标为负数,表示从尾开始计算(-1表示表尾)listNode *listIndex(list *list, long index);//重置前向迭代器void listRewind(list *list, listIter *li);//重置后向迭代器void listRewindTail(list *list, listIter *li);//旋转最后一个节点为表头结点void listRotate(list *list);/* Directions for iterators *///前向迭代器#define AL_START_HEAD 0 //后向迭代器#define AL_START_TAIL 1#endif /* __ADLIST_H__ */
实现:
#include <stdlib.h>#include "adlist.h"#include "zmalloc.h"/* * 创建一个新列表 * * 创建成功时返回列表,创建失败返回 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);}/* * 新建一个包含给定 value 的节点,并将它加入到列表的表头 * * 出错时,返回 NULL ,不执行动作。 * 成功时,返回传入的列表 * * T = O(1) */list *listAddNodeHead(list *list, void *value){ listNode *node; if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; node->value = value; if (list->len == 0) { // 第一个节点 list->head = list->tail = node; node->prev = node->next = NULL; } else { // 不是第一个节点 node->prev = NULL; node->next = list->head; list->head->prev = node; list->head = node; } list->len++; return list;}/* * 新建一个包含给定 value 的节点,并将它加入到列表的表尾 * * 出错时,返回 NULL ,不执行动作。 * 成功时,返回传入的列表 * * T = O(1) */list *listAddNodeTail(list *list, void *value){ listNode *node; if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; node->value = value; if (list->len == 0) { // 第一个节点 list->head = list->tail = node; node->prev = node->next = NULL; } else { // 不是第一个节点 node->prev = list->tail; node->next = NULL; list->tail->next = node; list->tail = node; } list->len++; return list;}/* * 创建一个包含值 value 的节点 * 并根据 after 参数的指示,将新节点插入到 old_node 的之前或者之后 * * T = O(1) * after == 非0 -〉之后 * after == 0 -〉之前 */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) { // 插入到 old_node 之后 node->prev = old_node; node->next = old_node->next; //如果之前的节点是tail,之后插入节点需要更新表尾 if (list->tail == old_node) { list->tail = node; } } else { // 插入到 old_node 之前 node->next = old_node; node->prev = old_node->prev; //如果之前的节点上是head,之前插入需要更新表头 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;}/* * 释放列表中给定的节点 * 清除节点私有值(private value)的工作由调用者完成 * * T = O(1) */void listDelNode(list *list, listNode *node){ // 处理前驱节点的指针 if (node->prev) node->prev->next = node->next; else//node是第一个节点 list->head = node->next; // 处理后继节点的指针 if (node->next) node->next->prev = node->prev; else//node是最后一个节点 list->tail = node->prev; // 释放节点值 if (list->free) list->free(node->value); // 释放节点 zfree(node); // 更新列表节点数量 list->len--;}/** 创建列表 list 的一个迭代器,迭代方向由参数 direction 决定* * 每次对迭代器调用 listNext() ,迭代器就返回列表的下一个节点** 这个函数不处理失败情形** 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;}/* * 释放迭代器 iter * * T = O(1) */void listReleaseIterator(listIter *iter) { zfree(iter);}/* * *将迭代器重置为从头开始的起始状态,应该叫listRewindHead,和下面的对应, * T = O(1) */void listRewind(list *list, listIter *li) { li->next = list->head; li->direction = AL_START_HEAD;}/* * 将迭代器重置为从尾开始的起始状态 * * T = O(1) */void listRewindTail(list *list, listIter *li) { li->next = list->tail; li->direction = AL_START_TAIL;}/* * 返回迭代器的当前节点 * * 可以使用 listDelNode() 删除当前节点,但是不可以删除其他节点。 * * 函数要么返回当前节点,要么返回 NULL ,因此,常见的用法是: * * iter = listGetIterator(list,<direction>); * while ((node = listNext(iter)) != NULL) { * doSomethingWith(listNodeValue(node)); * } * * T = O(1) */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;}/* * 复制整个列表,成功返回列表的副本,内存不足而失败时返回 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; //使用list的dup函数 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;}/* * 在列表中查找和 key 匹配的节点。 * * 如果列表带有匹配器,那么匹配通过匹配器来进行。 * 如果列表没有匹配器,那么直接将 key 和节点的值进行比对。 * * 匹配从表头开始,第一个匹配成功的节点会被返回 * 如果匹配不成功,返回 NULL 。 * * T = O(N),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;}/* * 根据给定索引,返回列表中对应的节点 * * 索引可以是正数,也可以是负数。 * 正数从 0 开始计数,由表头开始;负数从 -1 开始计数,由表尾开始(即-1代表倒数第一个,-2代表倒数第二个。。。。。)。 * * 如果给定索引超出列表的返回,返回 NULL 。 * * T = O(N),N 为列表的长度 */listNode *listIndex(list *list, long index) { listNode *n; if (index < 0) { //将由-1代表的表尾调整为0,从表尾开始遍历 index = (-index)-1; n = list->tail; while(index-- && n) n = n->prev; } else { n = list->head; while(index-- && n) n = n->next; } return n;}/* * 取出列表的尾节点,将它插入到表头,成为新的表头节点 * * T = O(1) */void listRotate(list *list) { listNode *tail = list->tail; // 列表只有一个元素 if (listLength(list) <= 1) return; // 取出尾节点 list->tail = tail->prev; list->tail->next = NULL; // 将它插入到表头 list->head->prev = tail; tail->prev = NULL; tail->next = list->head; list->head = tail;}
^_^双向链表无需总结^_^
0 0
- 【redis源码分析】双向链表---adlist
- 唯快不破:redis源码剖析02-adlist双向链表结构
- redis源码分析(9)redis源码链表学习总结 adlist.h adlist.c
- redis源码分析(adlist)
- Adlist 双向链表的实现 redis
- redis源码分析-adlist(链表)
- Redis源码分析(adlist)
- redis源码解读之双向链表————adlist.h文件
- redis源码阅读(2)---- adlist分析
- Redis源码分析(二)——链表adlist
- redis源码分析之数据结构(一)链表adlist.c
- Redis源码学习(1):adlist
- redis源码分析(四)-双向链表的实现
- Redis源码-数据结构之Adlist双端链表
- redis源码系列-数据结构(adlist/ziplist/dict)
- Redis源码阅读笔记—adlist
- Redis adlist
- Java LinkedList双向链表源码分析
- ORACLE 11G 新特性--可用性增强
- javascript判断浏览器类型
- VS2010常用插件介绍之Javascript插件
- 《Unix-Linux编程实践教程》读书笔记(四)
- 玩游戏无法全屏
- 【redis源码分析】双向链表---adlist
- 【足迹C++ primer】8.跳转语句
- 修改UINavigationBar的高度
- LeetCode-Validate Binary Search Tree
- 窗体的Resize事件,Load事件如何添加
- SSH:Hibernate log4j与自定义版本冲突问题
- 文件管理
- sed命令使用
- 对Lucene PhraseQuery的slop的理解(转载)