Redis学习——链表实现

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. 对外提供扩展,用户可以自定义查找,复制,释放的功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值