redis源码分析-adlist(链表)
来源:互联网 发布:idc数据库 编辑:程序博客网 时间:2024/05/19 06:17
一、简介
上一节,介绍了sds结构,接下来将介绍下redis的adlist(又称链表).redis的链表采用双向链表方式进行实现,代码位于src/adlist.h、src/adlist.c .
二、数据结构
C语言数据结构中双向链表结构由节点(listNode)、迭代器(listIterator)、容器(list)组成,redis也是如此。
节点
typedef struct listNode { struct listNode *prev; struct listNode *next; void *value;} listNode;
value:节点的内容 prev和next分别代表指向上一个节点与下一个节点的指针。
迭代器
typedef struct listIter { listNode *next; int direction;} listIter;
next:下一个节点指针 direction:遍历方向
容器
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;
head:表头指针 tail表尾指针 dup:复制函数 free:释放函数 match:遍历查找函数 len:链表长度
三、链表操作方法
上面简单地介绍了下链表的结构,下面将介绍链表的相关函数。链表的操作函数,相信大家在C语言数据结构都有接触过,实现代码比较简单。
listCreate: 创建一个list,并初始化,然后返回list对象。
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;}
listRelease: 与listCreate对应,该函数实现链表释放功能。
void listRelease(list *list){ unsigned long len; listNode *current, *next; current = list->head; len = list->len; while(len--) { next = current->next; if (list->free) list->free(current->value); zfree(current); current = next; } zfree(list);}
细心的读者可能注意到 list->free函数,这个函数是用于释放节点内容的空间。
listAddNodeHead: 添加数据至表头
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;}
listAddNodeTail: 与listAddNodeHead功能类似,添加数据至表尾。
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;}
listInsertNode: 将新节点添加至指定的节点之前/之后
//若after=0 ,将新节点插入到 old_node 之前。//若after=1 ,将新节点插入到 old_node 之后。list *listInsertNode(list *list, listNode *old_node, void *value, int after) { listNode *node; if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; node->value = value; //修改node前后指针指向 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; } } //如果新插入元素的前节点非空,则修改前节点的next指针指向 if (node->prev != NULL) { node->prev->next = node; } //如果新插入元素的后节点非空,则修改后节点的prev指针指向 if (node->next != NULL) { node->next->prev = node; } list->len++; return list;}
listDelNode: 删除指定节点操作
void listDelNode(list *list, listNode *node){ //修改node前节点的next指向 if (node->prev) node->prev->next = node->next; else list->head = node->next; //修改node前节点的prev指向 if (node->next) node->next->prev = node->prev; else list->tail = node->prev; //释放node节点 if (list->free) list->free(node->value); zfree(node); //len-1 list->len--;}
listGetIterator: 获取迭代器
//direction:有两个值//AL_START_HEAD : 从表头向表尾进行迭代//AL_START_TAIL : 从表尾到表头进行迭代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;}
listRewind: 重置链表指针到表头。与之对应,listRewindTail的功能为重置指针至表尾。
void listRewind(list *list, listIter *li) { li->next = list->head; li->direction = AL_START_HEAD;}
listNext: 该函数非常重要,在很多链表操作都有使用,实现了链表遍历的功能。
listNode *listNext(listIter *iter){ //获取下一个指针 listNode *current = iter->next; //如果current非空,则根据direction值,修改iter->next指向 if (current != NULL) { if (iter->direction == AL_START_HEAD) iter->next = current->next; else iter->next = current->prev; } return current;}
listDup: 复制链表功能
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; //重置orig指针至表头 listRewind(orig, &iter); //遍历orig 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;}
listSearchKey:根据给出的key对链表进行查找
listNode *listSearchKey(list *list, void *key){ listIter iter; listNode *node; //重置指针 listRewind(list, &iter); //遍历 while((node = listNext(&iter)) != NULL) { //对比value if (list->match) { if (list->match(node->value, key)) { return node; } } else { if (key == node->value) { return node; } } } return NULL;}
listIndex: 根据给出的下标,查找相应的节点。
//根据给出的下标进行搜索//index>=0: 顺序遍历,从表头往表尾进行遍历//index<0: 逆向遍历,从表尾往表头进行遍历listNode *listIndex(list *list, long index) { listNode *n; if (index < 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;}
四、总结
1. redis的链表采用了双向非循环链表设计。2. redis对链表并没有做太大的改造,与C语言数据结构链表功能大同小异。
0 0
- redis源码分析-adlist(链表)
- redis源码分析(adlist)
- Redis源码分析(adlist)
- Redis源码分析(二)——链表adlist
- redis源码分析之数据结构(一)链表adlist.c
- 【redis源码分析】双向链表---adlist
- redis源码阅读(2)---- adlist分析
- redis源码分析(9)redis源码链表学习总结 adlist.h adlist.c
- Redis源码学习(1):adlist
- Redis源码-数据结构之Adlist双端链表
- redis源码系列-数据结构(adlist/ziplist/dict)
- Redis源码阅读笔记—adlist
- Redis adlist
- redis学习笔记(2)---链表adlist
- Redis-数据结构-链表-adlist.h/listNode
- 唯快不破:redis源码剖析02-adlist双向链表结构
- redis之adlist
- (redis)adlist.h/adlist.c理解
- Android控件布局属性全解
- centos安装vim及其配置参考
- 19.Express 中使用模板引擎
- NodeJS 框架介绍
- Unity Cg Shader编程 第一章 第一节
- redis源码分析-adlist(链表)
- jQuery学习开始啦
- 生容易,活容易,生活不容易
- php实现简单的SQL Builder
- 能ping通Linux但是ssh连不上问题解决方法
- 如何十倍提高你的webpack构建效率
- Linux学习——NFS服务介绍及安装配置方法
- java初始化顺序
- 快速排序-java实现