您的位置:首页 > 数据库 > Redis

redis源码分析-adlist(链表)

2016-07-10 17:22 423 查看

一、简介

上一节,介绍了sds结构,接下来将介绍下redis的adlist(又称链表).redis的链表采用双向链表方式进行实现,代码位于src/adlist.h、src/adlist.c .


二、数据结构

C语言数据结构中双向链表结构由节点(listNode)、迭代器(listIterator)、容器(list)组成,redis也是如此。


节点

typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;


value:节点的内容 prev和next分别代表指向上一个节点与下一个节点的指针。

迭代器

typedef struct listIter {
listNode *next;
int direction;
} listIter;


next:下一个节点指针 direction:遍历方向

容器

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;


head:表头指针 tail表尾指针 dup:复制函数 free:释放函数 match:遍历查找函数 len:链表长度

三、链表操作方法

上面简单地介绍了下链表的结构,下面将介绍链表的相关函数。链表的操作函数,相信大家在C语言数据结构都有接触过,实现代码比较简单。


listCreate: 创建一个list,并初始化,然后返回list对象。

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: 与listCreate对应,该函数实现链表释放功能。

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);
zfree(current);
current = next;
}
zfree(list);
}


细心的读者可能注意到 list->free函数,这个函数是用于释放节点内容的空间。

listAddNodeHead: 添加数据至表头

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;
}


listAddNodeTail: 与listAddNodeHead功能类似,添加数据至表尾。

list *listAddNodeTail(list *list, <
4000
span class="hljs-literal">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: 将新节点添加至指定的节点之前/之后

//若after=0 ,将新节点插入到 old_node 之前。
//若after=1 ,将新节点插入到 old_node 之后。
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
listNode *node;

if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;
//修改node前后指针指向
if (after) {
node->prev = old_node;
node->next = old_node->next;
if (list->tail == old_node) {
list->tail = node;
}
} else {
node->next = old_node;
node->prev = old_node->prev;
if (list->head == old_node) {
list->head = node;
}
}
//如果新插入元素的前节点非空,则修改前节点的next指针指向
if (node->prev != NULL) {
node->prev->next = node;
}
//如果新插入元素的后节点非空,则修改后节点的prev指针指向
if (node->next != NULL) {
node->next->prev = node;
}
list->len++;
return list;
}


listDelNode: 删除指定节点操作

void listDelNode(list *list, listNode *node)
{

//修改node前节点的next指向
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
//修改node前节点的prev指向
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
//释放node节点
if (list->free) list->free(node->value);
zfree(node);
//len-1
list->len--;
}


listGetIterator: 获取迭代器

//direction:有两个值
//AL_START_HEAD : 从表头向表尾进行迭代
//AL_START_TAIL : 从表尾到表头进行迭代
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;
}


listRewind: 重置链表指针到表头。与之对应,listRewindTail的功能为重置指针至表尾。

void listRewind(list *list, listIter *li)
{
li->next = list->head;
li->direction = AL_START_HEAD;
}


listNext: 该函数非常重要,在很多链表操作都有使用,实现了链表遍历的功能。

listNode *listNext(listIter *iter)
{
//获取下一个指针
listNode *current = iter->next;
//如果current非空,则根据direction值,修改iter->next指向
if (current != NULL) {
if (iter->direction == AL_START_HEAD)
iter->next = current->next;
else
iter->next = current->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;
//重置orig指针至表头
listRewind(orig, &iter);
//遍历orig
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) {
//对比value
if (list->match) {
if (list->match(node->value, key)) {
return node;
}
} else {
if (key == node->value) {
return node;
}
}
}
return NULL;
}


listIndex: 根据给出的下标,查找相应的节点。

//根据给出的下标进行搜索
//index>=0: 顺序遍历,从表头往表尾进行遍历
//index<0: 逆向遍历,从表尾往表头进行遍历
listNode *listIndex(list *list, long index) {
listNode *n;

if (index < 0) {
index = (-index)-1
a486
;
n = list->tail;
while(index-- && n) n = n->prev;
} else {
n = list->head;
while(index-- && n) n = n->next;
}
return n;
}


四、总结

1. redis的链表采用了双向非循环链表设计。
2. redis对链表并没有做太大的改造,与C语言数据结构链表功能大同小异。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redis