Redis学习——链表实现

0. 前言

  Redis 中的链表是以通用链表的形式实现的,而对于链表的用途来说,主要的功能就是增删改查,所以对于查找来说,redis其提供了一个match函数指针,用户负责实现其具体的匹配操作,从而实现通用化。

  涉及的文件:adlist.h/adlist.c

1. 数据结构

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;                         //表尾
    void *(*dup)(void *ptr);        //用于复制ptr值,实现深度复制
    void (*free)(void *ptr);           //释放对应类型结构的内存
    int (*match)(void *ptr, void *key); //自定义匹配key
    unsigned long len;                  //节点数量
} list;

 

#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))

  其中提供了dup,free,match的函数指针,用户可以通过设置该函数指针,来存取特定类型的数据。

2. API实现:

  只提取几个主要的API,该文件完整的注释在GitHud上(用户名:jabnih)

a. listRelease

  对于释放链表的操作,其中对于每个节点的释放会判断用户是否设置了free函数,若有则执行用户的操作,用以释放特定类型数据。例如:value为指向一个从堆分配的字符数组,在释放该节点的时候,就需要先释放value内存

对于free可以实现为:

1 void free(void * value)
2 {
3     if( value )
4         free( (char *)value );
5 }
 1  //释放链表
 2 void listRelease(list *list)
 3 {
 4     unsigned long len;
 5     listNode *current, *next;
 6
 7     current = list->head;
 8     len = list->len;
 9     while(len--) {
10         next = current->next;
11         //若设置了free函数,则调用该自定义free函数
12         if (list->free) list->free(current->value);
13
14         zfree(current);
15         current = next;
16     }
17     zfree(list);
18 }

b. listDup

  当执行复制的时候,对于设置了dup函数可以实现深度复制或自定义复制的功能。

 1 //复制链表,若有链表有dup,则调用该函数进行深度复制,否则直接复制节点的值(浅复制)
 2 list *listDup(list *orig)
 3 {
 4     list *copy;
 5     listIter *iter;
 6     listNode *node;
 7
 8     if ((copy = listCreate()) == NULL)
 9         return NULL;
10     copy->dup = orig->dup;
11     copy->free = orig->free;
12     copy->match = orig->match;
13     iter = listGetIterator(orig, AL_START_HEAD);
14     while((node = listNext(iter)) != NULL) {
15         //遍历整个链表
16         void *value;
17
18         if (copy->dup) {
19             //深度复制
20             value = copy->dup(node->value);
21             if (value == NULL) {
22                 //复制出错
23                 listRelease(copy);
24                 listReleaseIterator(iter);
25                 return NULL;
26             }
27         } else
28             //浅复制
29             value = node->value;
30
31         //将复制后的节点添加的copy链表尾部
32         if (listAddNodeTail(copy, value) == NULL) {
33             listRelease(copy);
34             listReleaseIterator(iter);
35             return NULL;
36         }
37     }
38     listReleaseIterator(iter);
39     return copy;
40 }

c. listSearchKey

 1  //查找节点,如果设置了match方法,则使用match方法比较,否则仅仅比较节点的value值
 2 listNode *listSearchKey(list *list, void *key)
 3 {
 4     listIter *iter;
 5     listNode *node;
 6
 7     iter = listGetIterator(list, AL_START_HEAD);
 8     while((node = listNext(iter)) != NULL) {
 9         if (list->match) {
10             if (list->match(node->value, key)) {
11                 //这里可以将下面两条语句改为break(下同),最后return NULL改为 return node
12                 listReleaseIterator(iter);
13                 return node;
14             }
15         } else {
16             if (key == node->value) {
17                 listReleaseIterator(iter);
18                 return node;
19             }
20         }
21     }
22     listReleaseIterator(iter);
23     return NULL;
24 }

3. 总结

  1. 通用链表实现

  2. 对外提供扩展,用户可以自定义查找,复制,释放的功能。

时间: 2024-08-30 14:46:16

Redis学习——链表实现的相关文章

Redis学习笔记

Redis学习笔记:Redis是什么?redis是开源BSD许可高级的key-vlue存储系统可以用来存储字符串哈希结构链表.结构.集合,因此常用来提供数据结构服务. redis和memcache相比的独特之处:1.redis可以用来做存储,而memcache是用来做缓存 这个特点主要因为其有"持久化"的功能.2.存储的数据有"结构",对于memcache来说,存储的数据只有1种类型"字符串"而 redis则可以存储字符串.链表.哈希机构.集合.

Redis学习手册(目录)

Posted on 2012-04-16 07:40 Stephen_Liu 阅读(29155) 评论(25) 编辑 收藏 为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后就是上手容易,操作简单.记得在刚刚接触Redis的时候,由于当时项目的工期相当紧张,留给我们做出选择的空间也是非常有限,一旦技术决策失误,造成的后果也比较严重.所以在做出决定之

Redis学习笔记~目录

redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hashs(哈希类型).这些数据类型都 支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.在此基础上,redis支持各种不同方式的排 序.与memcached一样,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更

Redis学习手册

为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后就是上手容易,操作简单.记得在刚刚接触Redis的时候,由于当时项目的工期相当紧张,留给我们做出选择的空间也是非常有限,一旦技术决策失误,造成的后果也比较严重.所以在做出决定之前,我不仅快速的浏览了Redis官网文档,而且还熬夜搜集了很多网上的相关技术文章.在经过一通折腾之后,毅然决然的选择了它,现

Redis学习手册——转载

转载出处:http://www.cnblogs.com/stephen-liu74/archive/2012/04/16/2370212.html 为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后就是上手容易,操作简单.记得在刚刚接触Redis的时候,由于当时项目的工期相当紧张,留给我们做出选择的空间也是非常有限,一旦技术决策失误,造成的后果也比

redis学习笔记(9)---对象robject

robject 之前对redis基本的数据结构分别进行了简单的介绍,包括字符串.链表.哈希表.整数集合.压缩列表.压缩字典等,但是redis并不是直接使用这些数据结构来实现key-value对数据库的,而是基于这些数据结构为每一个对象创建一个对象robject.robject对象再根据数据类型,来选择合适的底层数据结构来存储数据. robject的定义如下: typedef struct redisObject { unsigned type:4; unsigned encoding:4; un

Redis学习二

Redis学习二 标签(空格分隔): Redis 一,link 链表结构 1,lpush key value (rpush插入到链表尾部) 作用: 把值插入到链接头部 2,rpop key(lpop key 返回并删除链表的头元素) 作用: 返回并删除链表尾元素 3,lrange key start stop 作用: 返回链表中[start ,stop]中的元素 规律: 左数从0开始,右数从-1开始 lrange link 0 2 lrange link 0 -1 4,lrem key coun

Redis 学习(二) —— 数据类型及操作

Redis支持string.list.set.zset.hash等数据类型,这一篇学习redis的数据类型.命令及某些使用场景. 一.String,字符串 字符串是 Redis 最基本的数据类型.一个字符串最大为 512M 字节.字符串数据类型适用于很多场景,例如,缓存 HTML 片段或者页面. Redis 字符串是二进制安全的,也就是说,一个 Redis 字符串可以包含任意类型的数据,例如一张 JPEG 图像,或者一个序列化的对象. 我们可以把字符串当做位数组(位图)来处理,很容易统计一些基于

为什么C/C++程序员都要阅读Redis源码之:Redis学习事件驱动设计

为什么我说C/C++程序员都要阅读Redis源码 主要原因就是『简洁』.如果你用源码编译过Redis,你会发现十分轻快,一步到位.其他语言的开发者可能不会了解这种痛,作为C/C++程序员,如果你源码编译安装过Nginx/Grpc/Thrift/Boost等开源产品,你会发现有很多依赖,而依赖本身又有依赖,十分痛苦.通常半天一天就耗进去了.由衷地羡慕 npm/maven/pip/composer/...这些包管理器.而Redis则给人惊喜,一行make了此残生. 除了安装过程简洁,代码也十分简洁.