redis学习笔记(2)---链表adlist

adlist

  redis通过prev、next指针实现了双向链表adlist,并通过void*指向数据,用来实现泛型。
  与list相关的命令主要有:LPOP,LPUSH,RPOP,RPUSH,LLEN  

定义

typedef struct listNode { //链表节点
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

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;

  list通过head、tail分别保存了链表的头节点和尾部节点,这样LPOP,LPUSH,RPOP,RPUSH这几个操作的时间复杂度就都是O(1)了。
  同时链表还保存了链表长度len,这样获取链表长度操作LLEN的时间复杂度也是O(1)。

迭代器

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

  adlist还通过listIter来实现了迭代器,通过next指向下一个节点,通过direction来指示迭代器迭代的方向。其中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;
}

  然后就可以通过next函数利用迭代器遍历链表了


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

示意图

  一个双向链表的示意图如下:
  redis学习笔记(2)---链表adlist_第1张图片

链表的特点:

  1、双向
  2、无环
  3、带头节点和尾部节点
  4、带链表长度
  5、多态,通过void *来保存数据,并通过list结构中的dup、free、match函数指针为不同类型的数据设置特定的函数。因此链表可以用于保存不同类型的数据

本文所引用的源码全部来自Redis3.0.7版本。

你可能感兴趣的:(redis学习笔记(2)---链表adlist)