簡介
鏈表在Redis中的應用非常廣泛,比如列表鍵的底層實現之一就是鏈表。當一個列表鍵包含了數量表較多的元素,又或列表中包含的元素都是比較長的字符串時,Redis就會用鏈表作爲列表鍵的底層實現。
redis鏈表實現所需的結構
/*
* 雙端鏈表節點
*/
typedef struct listNode {
// 前置節點
struct listNode *prev;
// 後置節點
struct listNode *next;
// 節點的值
void *value;
} listNode;
/* Directions for iterators
*
* 迭代器進行迭代的方向
*/
// 從表頭向表尾進行迭代
#define AL_START_HEAD 0
// 從表尾到表頭進行迭代
#define AL_START_TAIL 1
/*
* 雙端鏈表迭代器
*/
typedef struct listIter {
// 當前迭代到的節點
listNode *next;
// 迭代的方向
int direction;
} listIter;
/*
* 雙端鏈表結構
*/
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;
Redis鏈表特性
Redis鏈表操作主要API實現
/*
* 創建一個新的鏈表
*
* 創建成功返回鏈表,失敗返回 NULL 。
*
* T = O(1)
*/
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;
}
/*
* 釋放整個鏈表,以及鏈表中所有節點
*
* T = O(N)
*/
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);
}
/*
* 將一個包含有給定值指針 value 的新節點添加到鏈表的表頭
*
* 如果爲新節點分配內存出錯,那麼不執行任何動作,僅返回 NULL
*
* 如果執行成功,返回傳入的鏈表指針
*
* T = O(1)
*/
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;
}
/*
* 將一個包含有給定值指針 value 的新節點添加到鏈表的表尾
*
* 如果爲新節點分配內存出錯,那麼不執行任何動作,僅返回 NULL
*
* 如果執行成功,返回傳入的鏈表指針
*
* T = O(1)
*/
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;
}
/*
* 創建一個包含值 value 的新節點,並將它插入到 old_node 的之前或之後
*
* 如果 after 爲 0 ,將新節點插入到 old_node 之前。
* 如果 after 爲 1 ,將新節點插入到 old_node 之後。
*
* T = O(1)
*/
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
listNode *node;
// 創建新節點
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
// 保存值
node->value = value;
// 將新節點添加到給定節點之後
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;
}
}
// 更新新節點的前置指針
if (node->prev != NULL) {
node->prev->next = node;
}
// 更新新節點的後置指針
if (node->next != NULL) {
node->next->prev = node;
}
// 更新鏈表節點數
list->len++;
return list;
}
/*
* 從鏈表 list 中刪除給定節點 node
*
* 對節點私有值(private value of the node)的釋放工作由調用者進行。
*
* T = O(1)
*/
void listDelNode(list *list, listNode *node)
{
// 調整前置節點的指針
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
// 調整後置節點的指針
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
// 釋放值
if (list->free) list->free(node->value);
// 釋放節點
zfree(node);
// 鏈表數減一
list->len--;
}
/*
* 爲給定鏈表創建一個迭代器,
* 之後每次對這個迭代器調用 listNext 都返回被迭代到的鏈表節點
*
* direction 參數決定了迭代器的迭代方向:
* AL_START_HEAD :從表頭向表尾迭代
* AL_START_TAIL :從表尾想表頭迭代
*
* T = O(1)
*/
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;
}
/* Release the iterator memory */
/*
* 釋放迭代器
*
* T = O(1)
*/
void listReleaseIterator(listIter *iter) {
zfree(iter);
}
/*
* 返回迭代器當前所指向的節點。
*
* 刪除當前節點是允許的,但不能修改鏈表裏的其他節點。
*
* 函數要麼返回一個節點,要麼返回 NULL ,常見的用法是:
*
* iter = listGetIterator(list,<direction>);
* while ((node = listNext(iter)) != NULL) {
* doSomethingWith(listNodeValue(node));
* }
*
* T = O(1)
*/
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;
}
/*
* 查找鏈表 list 中值和 key 匹配的節點。
*
* 對比操作由鏈表的 match 函數負責進行,
* 如果沒有設置 match 函數,
* 那麼直接通過對比值的指針來決定是否匹配。
*
* 如果匹配成功,那麼第一個匹配的節點會被返回。
* 如果沒有匹配任何節點,那麼返回 NULL 。
*
* T = O(N)
*/
listNode *listSearchKey(list *list, void *key)
{
listIter *iter;
listNode *node;
// 迭代整個鏈表
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;
}
/*
* 返回鏈表在給定索引上的值。
*
* 索引以 0 爲起始,也可以是負數, -1 表示鏈表最後一個節點,諸如此類。
*
* 如果索引超出範圍(out of range),返回 NULL 。
*
* T = O(N)
*/
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;
}
還有一些宏定義
// 返回給定鏈表所包含的節點數量
// T = O(1)
#define listLength(l) ((l)->len)
// 返回給定鏈表的表頭節點
// T = O(1)
#define listFirst(l) ((l)->head)
// 返回給定鏈表的表尾節點
// T = O(1)
#define listLast(l) ((l)->tail)
// 返回給定節點的前置節點
// T = O(1)
#define listPrevNode(n) ((n)->prev)
// 返回給定節點的後置節點
// T = O(1)
#define listNextNode(n) ((n)->next)
// 返回給定節點的值
// T = O(1)
#define listNodeValue(n) ((n)->value)
// 將鏈表 l 的值複製函數設置爲 m
// T = O(1)
#define listSetDupMethod(l,m) ((l)->dup = (m))
// 將鏈表 l 的值釋放函數設置爲 m
// T = O(1)
#define listSetFreeMethod(l,m) ((l)->free = (m))
// 將鏈表的對比函數設置爲 m
// T = O(1)
#define listSetMatchMethod(l,m) ((l)->match = (m))
// 返回給定鏈表的值複製函數
// T = O(1)
#define listGetDupMethod(l) ((l)->dup)
// 返回給定鏈表的值釋放函數
// T = O(1)
#define listGetFree(l) ((l)->free)
// 返回給定鏈表的值對比函數
// T = O(1)
#define listGetMatchMethod(l) ((l)->match)