redis源码分析(3)-- 基本数据结构双链表list
一、双链表结构
redis中实现的双链表结构体如下:
1 typedef struct list { 2 listNode *head; # 链表头 3 listNode *tail; # 链表尾 4 void *(*dup)(void *ptr); # 复制链表函数 5 void (*free)(void *ptr); # 释放节点函数 6 int (*match)(void *ptr, void *key); # 匹配函数 7 unsigned long len; # 链表节点个数 8 } list;
包含三个节点的list组成如图:
每个listNode的结构:
1 typedef struct listNode { 2 struct listNode *prev; 3 struct listNode *next; 4 void *value; 5 } listNode;
Redis链表list特点:
1、双端:每个节点包括前向指针prev和后级指针next,获取节点前后节点都是O(1)
2、无环:首节点prev=NULL,尾节点next=NULL
3、list结构包含表头指针和表尾指针,获取头尾节点时间复杂度O(1)
4、list包含节点计数器len,获取节点长度只需要O(1)
5、多态; 节点value为void*, 并且可以通过函数指针dup、free、match为节点设置属性。
二、list迭代器
链表其他操作比较简单,这里主要介绍list中的迭代器使用。先看下迭代器在遍历链表中的应用
1 listNode *listSearchKey(list *list, void *key) 2 { 3 listIter *iter; 4 listNode *node; 5 6 iter = listGetIterator(list, AL_START_HEAD); # 获取从头开始的迭代器 7 while((node = listNext(iter)) != NULL) { # 从迭代器依次获取下个节点,并开始遍历 8 if (list->match) { 9 if (list->match(node->value, key)) { 10 listReleaseIterator(iter); 11 return node; 12 } 13 } else { 14 if (key == node->value) { 15 listReleaseIterator(iter); 16 return node; 17 } 18 } 19 } 20 listReleaseIterator(iter); # 释放迭代器 21 return NULL; 22 }
获取迭代器源码:
1 listIter *listGetIterator(list *list, int direction) 2 { 3 listIter *iter; 4 5 if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL; 6 if (direction == AL_START_HEAD) # 根据direction,得到链表头或者链表尾节点 7 iter->next = list->head; 8 else 9 iter->next = list->tail; 10 iter->direction = direction; 11 return iter; 12 }
迭代器结构:
1 typedef struct listIter { 2 listNode *next; 3 int direction; 4 } listIter;
三、链表操作