概述
1.链表介绍
2.链表API
链表介绍
链表在Redis中的应用非常广泛,比如列表键list的底层实现就是使用的链表。除了列表键外,Redis的发布与订阅、慢查询、监视器等功能也用到了链表,Redis服务器本身还使用了链表来保存客户端连接状态,以后使用链表来构建客户端输出缓冲区。
链表在Redis的数据结构如下:
typedef struct listNode { struct listNode *prev; //前一个节点 struct listNode *next; //后一个节点,可以看出链表为双向链表 void *value; //节点值 } listNode;
其实可以通过多个listNode链接起来,就是一个双向链表,但是使用list结构来持有链表会更方便,如下:
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;
Redis中链表的特点:
1.双向,有prev和next指针指向前/后一个节点;
2.无环,header的prev和tail的next都指向null;
3.带表头和表尾指针,快速获取表头/尾;
4.带链表长度值;
5.多态,通过void* 来保存节点值,可以通过函数为节点值设置类型特定函数,所以链表能够保存各种不同类型的值。
链表API
添加头部节点,和基本链表操作类似
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; }
search节点
listNode *listSearchKey(list *list, void *key) { listIter *iter; listNode *node; iter = listGetIterator(list, AL_START_HEAD); //获取遍历器 while((node = listNext(iter)) != NULL) { //遍历节点 if (list->match) { //match函数不为空,即设置了链表的值比较函数 if (list->match(node->value, key)) { //根据match函数来比较 listReleaseIterator(iter); return node; } } else { //没设置,直接比较 if (key == node->value) { listReleaseIterator(iter); return node; } } } listReleaseIterator(iter); return NULL; }
遍历器
typedef struct listIter { //设置一个listIter遍历器 listNode *next; int direction; //direction值为AL_START_HEAD(0)头部节点开始,AL_START_TAIL(1)尾部节点开始 } listIter;
获取迭代器的方法:
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; //设置next节点为head else iter->next = list->tail; iter->direction = direction; return iter; }
然后通过next函数通过迭代器遍历:
/* 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)); * } * * */ 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; }