在redis中List列表中,主要功能有:
1 向指定的列表插入(弹出)数据,方向可以向前插入(弹出),也可以朝后插入(弹出)。指令为lpush,rpush,lpop,rpop
2 获取给定索引的元素,给定索引可以是区间(start, stop),指令为lindex,lrange
3 获取列表的长度,指令为llen
要想实现上述功能,首先想到的是链表。要做到两头插入或弹出,必须要有两个指针,分别指向链表的头和尾。同时有个计数来表明当前长度。为了让处在尾端的元素也能快速遍历,链表必须为双向列表。所以列表和列表节点都非常清楚了,用代码表示结构为:
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
typedef struct list {
listNode *head;
listNode *tail;
unsigned long len;
} list;
相信链表的插入,删除难不倒大家。这里重点说说链表的查找。
由于链表是双向的,故可以在两头方向上进行查找。在这里可以应用迭代器模式来抽象查找的区别。具体代码如下:
listNode *listSearchKey(list *list, void *key)
{
listNode *node;
listIter* iter = listGetIterator(list, AL_START_HEAD);
while ((node = listNext(iter)) != NULL) {
if (list->match) {
if (list->match(node->value, key)) {
listReleaseIterator(iter);
return node;
}
}
else {
if (key == node->value) {
listReleaseIterator(iter);
return node;
}
}
}
listReleaseIterator(iter);
return NULL;
}
在listGetIterator()中指定访问链表的方向,listNext()函数会根据方向走下去:
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;
}
这节比较简单,相信有数据结构基础的人都很容易懂。完整代码:
https://github.com/shonm520/test_redis