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

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

2016-05-03 20:03 477 查看

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


示意图

  一个双向链表的示意图如下:

  


链表的特点:

  1、双向

  2、无环

  3、带头节点和尾部节点

  4、带链表长度

  5、多态,通过void *来保存数据,并通过list结构中的dup、free、match函数指针为不同类型的数据设置特定的函数。因此链表可以用于保存不同类型的数据

本文所引用的源码全部来自Redis3.0.7版本。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: