号外号外,新建Redis交流讨论群:332160890,欢迎加入!!
类型介绍
这部分是redis自定义的链表类型,该链表为双向链表,可以自定义存储类型,另外可以自定义释放、拷贝、对比函数等功能,提供的操作也比较丰富,包括创建、添加、插入、删除、索引等步骤,还拥有迭代器功能。
代码分析
自定义类型
链表节点,双向链表
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); //复制内存空间
void (*free)(void *ptr); //自定义释放空间函数,用于释放value占用空间
int (*match)(void *ptr, void *key); //自定义比较函数
unsigned long len; //链表长度
} list;
定义变量
代码分解
listCreate,创建一个链表,内部不存储元素,创建失败返回NULL;
list *listCreate(void)
{
struct list *list;
if ((list = zmalloc(sizeof(*list))) == NULL)
return NULL;
list->head = list->tail = NULL;
list->len = 0;
list->dup = NULL;
list->free = NULL;
list->match = NULL;
return list;
}
listRelease,释放链表,由于每个元素都是实际分配的内存,必须使用zfree函数释放;
void listRelease(list *list)
{
unsigned long len;
listNode *current, *next; //指针变量
current = list->head;
len = list->len;
while(len--) {
next = current->next;
if (list->free) list->free(current->value); //释放当前value占用的内存
zfree(current); //释放该节点结构体占用的内存空间
current = next;
}
zfree(list);
}
listAddNodeHead,在链表头部添加一个value,分配一个节点放置在链表头;
list *listAddNodeHead(list *list, void *value)
{
listNode *node;
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL; //申请内存
node->value = value;
//这里是不是该判断下list是否为NULL ?
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的头节点设置为该节点
}
list->len++;
return list; //返回之前传入的链表指针
}
listAddNodeTail,为当前value分配一个节点并放置到链表尾部;
list *listAddNodeTail(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 = list->tail; //该节点的前置节点设置为链表的尾部节点
node->next = NULL; //该节点的后置节点置为空
list->tail->next = node; //链表之前的尾部节点的后置节点设置为当前节点
list->tail = node; //链表的尾部设置为当前节点
}
list->len++;
return list;
}
listInsertNode,插入某个value,分配该节点插入到old_node前后,after来表示前后方向;
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
listNode *node;
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL; //分配内存
node->value = value;
if (after) { //表示插入到某个节点之后
node->prev = old_node; //设置当前节点的前置节点为某个节点
node->next = old_node->next; //设置当前节点的后置节点为某个节点的后置节点
if (list->tail == old_node) {
list->tail = node; //如果old_node是链表尾部,则更新尾部
}
} else { //表示插入到某个节点之前
node->next = old_node; //设置当前节点的后置节点为某个节点
node->prev = old_node->prev; //设置当前节点的前置节点为某个节点的前置节点
if (list->head == old_node) {
list->head = node; //如果某个节点原本为链表头节点,更新链表头结点
}
}
if (node->prev != NULL) {
node->prev->next = node; //如果当前链表的前置节点不为空,则设置当前节点的前置节点的后置节点为当前节点
}
if (node->next != NULL) {
node->next->prev = node; //如果当前链表的后置节点不为空,则设置当前节点的后置节点的前置节点为当前节点
}
list->len++;
return list;
}
listDelNode,删除某个节点;
void listDelNode(list *list, listNode *node)
{
if (node->prev)
node->prev->next = node->next; //如果待删除节点的前置节点存在,则将该前置节点的后置节点设置为待删除节点的后置节点
else
list->head = node->next; //否则将链表的头部节点设置待删除节点的后置节点,这是因为双向链表中只有头节点无前置节点,只有尾节点无后置节点
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
if (list->free) list->free(node->value); //如果有自定义内存释放函数,调用去释放节点的value信息
zfree(node); //释放该节点
list->len--;
}
listGetIterator,根据设定的方向(正向还是反向)获取迭代器,这类迭代器比较简单,不涉及锁操作;
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;
}
listReleaseIterator,释放迭代器内存;
void listReleaseIterator(listIter *iter) {
zfree(iter);
}
listRewind,为一个迭代器,设置正向;
void listRewind(list *list, listIter *li) {
li->next = list->head;
li->direction = AL_START_HEAD;
}
listRewindTail,为一个迭代器,设置反向;
void listRewindTail(list *list, listIter *li) {
li->next = list->tail;
li->direction = AL_START_TAIL;
}
listNext,根据迭代器获取下一个节点;
listNode *listNext(listIter *iter)
{
listNode *current = iter->next;
if (current != NULL) {
if (iter->direction == AL_START_HEAD)
iter->next = current->next; //正向,为当前节点的next
else
iter->next = current->prev; //反向,为当前节点的prev
}
return current;
}
listDup,拷贝一个链表;
list *listDup(list *orig)
{
list *copy;
listIter iter;
listNode *node;
if ((copy = listCreate()) == NULL)
return NULL; //创建先链表,待拷贝
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match; //将属性函数,直接复制
listRewind(orig, &iter); //获取迭代器
while((node = listNext(&iter)) != NULL) { //迭代
void *value;
if (copy->dup) { //如果指定复制方法
value = copy->dup(node->value);
if (value == NULL) { //拷贝出错,直接退出
listRelease(copy);
return NULL;
}
} else
value = node->value; //未指定指向同一地址,两个都可以修改
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy); //添加到链表尾部
return NULL;
}
}
return copy;
}
listSearchKey,按key查找;
listNode *listSearchKey(list *list, void *key)
{
listIter iter;
listNode *node;
listRewind(list, &iter); //分配迭代器
while((node = listNext(&iter)) != NULL) {
if (list->match) { //如果有匹配函数
if (list->match(node->value, key)) {
return node;
}
} else { //没有直接对比地址
if (key == node->value) {
return node;
}
}
}
return NULL; //未找到,返回
}
listIndex,获取当前索引对应的节点,从0开始计数;
listNode *listIndex(list *list, long index) {
listNode *n;
if (index < 0) { //index为负,表示从尾部开始
index = (-index)-1;
n = list->tail;
while(index-- && n) n = n->prev;
} else { //否则从正向开始
n = list->head;
while(index-- && n) n = n->next;
}
return n;
}
listRotate,反转链表,这里只是将头尾节点呼唤;
void listRotate(list *list) {
listNode *tail = list->tail;
if (listLength(list) <= 1) return;
/* Detach current tail */
list->tail = tail->prev; //将尾部节点脱离链表
list->tail->next = NULL;
/* Move it as head */
list->head->prev = tail; //添加到头部
tail->prev = NULL;
tail->next = list->head;
list->head = tail;
}