Redis源码分析笔记3-redis的数据类型-链表
来源:互联网 发布:开淘宝护肤品店 编辑:程序博客网 时间:2024/06/07 13:37
简介:
本节主要和大家一起讨论redis五种基本类型中的链表。
分别从链表的定义、实现、迭代器的实现等几个方面讨论。
链表
链表节点的定义
Radis链表的实现在文件src/adlist.h和src/adlist.c中,链表节点的定义没有什么特殊点。如下所示:
/* * 双端链表节点 */typedef struct listNode { // 前置节点 struct listNode *prev; // 后置节点 struct listNode *next; // 节点的值 void *value;} listNode;
双链表的实现
/* * 双端链表结构 */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;
这个双链表结构的实现有一个比较特殊的地方就是dup、free、match三个函数指针。凭借经验猜测,这是为了实现不同类型的多态链表。我们继续往下看来印证我们的猜测。
代码继续往下看就看到了链表的多态的实现。如下图所示:
// 将链表 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)
图12
链表的比较常见的操作是用宏定义实现的,没有什么特殊的地方,如下图所示:
/* 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)
图13
双端迭代器
看到双端迭代器的定义,我瞬间兴奋了。终于可以一睹迭代器的实现了。我们首先看一下迭代器的定义。
/* * 双端链表迭代器 */typedef struct listIter { // 当前迭代到的节点 listNode *next; // 迭代的方向 int direction;} listIter;
图14
然后我们看一下迭代器的实现:
/* Returns a list iterator 'iter'. After the initialization every * call to listNext() will return the next element of the list. * * This function can't fail. *//* * 为给定链表创建一个迭代器, * 之后每次对这个迭代器调用 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;}/* Release the iterator memory *//* * 释放迭代器 * * T = O(1) */void listReleaseIterator(listIter *iter) { zfree(iter);}/* Create an iterator in the list private iterator structure *//* * 将迭代器的方向设置为 AL_START_HEAD , * 并将迭代指针重新指向表头节点。 * * T = O(1) */void listRewind(list *list, listIter *li) { li->next = list->head; li->direction = AL_START_HEAD;}/* * 将迭代器的方向设置为 AL_START_TAIL , * 并将迭代指针重新指向表尾节点。 * * T = O(1) */void listRewindTail(list *list, listIter *li) { li->next = list->tail; li->direction = AL_START_TAIL;}/* Return the next element of an iterator. * It's valid to remove the currently returned element using * listDelNode(), but not to remove other elements. * * The function returns a pointer to the next element of the list, * or NULL if there are no more elements, so the classical usage patter * is: * * iter = listGetIterator(list,<direction>); * while ((node = listNext(iter)) != NULL) { * doSomethingWith(listNodeValue(node)); * } * * *//* * 返回迭代器当前所指向的节点。 * * 删除当前节点是允许的,但不能修改链表里的其他节点。 * * 函数要么返回一个节点,要么返回 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;}
图15
总结:
这样看下来其实迭代器的实现也就是故作神秘,逻辑很简单。
看这个链表实现的代码的收获就是把链表这个数据结构完整的复习了一遍,并且学会了如何给链表设置迭代器了。
0 0
- Redis源码分析笔记3-redis的数据类型-链表
- Redis源码分析笔记4-redis的数据类型-字典
- redis源码分析笔记2- redis的数据类型-动态字符串sds
- 【Redis笔记-3】Redis数据类型
- Redis笔记(三)Redis的数据类型
- redis源码学习笔记(一)--数据类型
- redis源码分析(3)——redis链表
- [Redis学习笔记]-Redis数据类型
- redis基本数据类型分析
- Redis-数据类型分析
- redis源码分析-adlist(链表)
- Redis复习笔记2—Redis的数据类型
- redis学习笔记二(redis的数据类型)
- redis爬坑记二) redis的数据类型
- 【Redis源码剖析】 - Redis数据类型之redisObject
- Redis源码分析(八)——数据类型 redisObject
- Redis数据类型的基本命令(笔记)
- Redis笔记3:数据类型之字符串(String)
- 南宁患了便秘去哪治
- 组件映射
- 南宁便秘哪里治疗好
- Swift’s Answer to #pragma mark, FIXME and TODO
- 南宁哪里能诊断便秘
- Redis源码分析笔记3-redis的数据类型-链表
- CAAnimation的iOS动画效果和实现
- 10大最适合编程的字体推荐下载,让代码看起来更美更舒服!
- linux主机互信
- 自定义控件其实很简单1/12
- 数据仓库中的基础术语介绍
- opencv中BackgroundSubtractorMOG类中的背景提取
- 南宁去哪里看便秘好
- 南宁哪里看便秘最好