redis源码学习笔记--双向列表

在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








猜你喜欢

转载自blog.csdn.net/zxm342698145/article/details/80845122