redis源码分析-adlist(链表)

来源:互联网 发布:idc数据库 编辑:程序博客网 时间:2024/05/19 06:17

一、简介

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

二、数据结构

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

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

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

  2. 迭代器

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

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

  3. 容器

    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语言数据结构都有接触过,实现代码比较简单。
  1. 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;}
  2. 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函数,这个函数是用于释放节点内容的空间。

  3. 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;}
  4. listAddNodeTail: 与listAddNodeHead功能类似,添加数据至表尾。

    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;}
  5. 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;}
  6. 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--;}
  7. 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;}
  8. listRewind: 重置链表指针到表头。与之对应,listRewindTail的功能为重置指针至表尾。

    void listRewind(list *list, listIter *li) {    li->next = list->head;    li->direction = AL_START_HEAD;}
  9. 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;}
  10. 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;}
  11. 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;}
  12. listIndex: 根据给出的下标,查找相应的节点。

    //根据给出的下标进行搜索//index>=0: 顺序遍历,从表头往表尾进行遍历//index<0: 逆向遍历,从表尾往表头进行遍历listNode *listIndex(list *list, long index) {    listNode *n;    if (index < 0) {        index = (-index)-1;        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语言数据结构链表功能大同小异。
0 0