redis原始碼閱讀-資料結構篇-雙端列表adlist
阿新 • • 發佈:2021-06-10
目錄
3. 雙端連結串列 adlist.h 和 adlist.c
資料結構定義
-
節點
// 節點 typedef struct listNode { struct listNode *prev; struct listNode *next; void *value; } listNode;
-
連結串列
// 連結串列 typedef struct list { listNode *head; listNode *tail; unsigned long len; // 節點值複製、釋放和對比函式,用於使用者自定義,否則直接操作value指標 void *(*dup)(void *ptr); void (*free)(void *ptr); int (*match)(void *ptr, void *key); } list;
-
迭代器
// 迭代器 typedef struct listIter { listNode *next; // 當前節點 int direction; // 迭代的方向 } listIter;
-
部分巨集定義
// some macros #define listLength(l) ((l)->len) #define listSetDupMethod(l,m) ((l)->dup = (m)) ...
建構函式
// 建立空連結串列,記憶體不足返回NULL 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; }
解構函式
// 釋放連結串列,會釋放所有節點指標和連結串列指標,可呼叫自定義函式
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);
}
get iter
// 建立新迭代器
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;
}
delete iter
// 釋放迭代器
void listReleaseIterator(listIter *iter) {
zfree(iter);
}
reset iter
// 重置迭代器
void listRewind(list *list, listIter *li) {
li->next = list->head;
li->direction = AL_START_HEAD;
}
void listRewindTail(list *list, listIter *li) {
li->next = list->tail;
li->direction = AL_START_TAIL;
}
迭代
// 獲取當前節點
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;
}
add node to head
// 新增節點到表頭,到表尾同理
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;
}
insert node
// 插入新節點到 old_node 之前或之後
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;
}
delete node
// 刪除 node 節點,可呼叫自定義函式
void listDelNode(list *list, listNode *node) {
// 更新 prev 節點
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
// 更新 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--;
}
get node by key
// 匹配節點 value 和 key,可呼叫自定義函式,否則比較指標
// 成功返回第一個
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;
}
get node by index
// 返回第 index 個節點
// 可為負數,-1 表示最後一個
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;
}
copy list
// copy 新連結串列,可呼叫自定義copy,否則淺拷貝
list *listDup(list *orig) {
list *copy;
listIter *iter;
listNode *node;
// 建立新連結串列
if ((copy = listCreate()) == NULL)
return NULL;
// 設定節點值處理函式
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match;
// 迭代整個輸入連結串列
iter = listGetIterator(orig, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
void *value;
// 複製節點值到新節點
if (copy->dup) {
value = copy->dup(node->value);
if (value == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
} else
value = node->value;
// 將節點新增到連結串列
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
}
// 釋放迭代器
listReleaseIterator(iter);
// 返回副本
return copy;
}
rotate
// 迴圈右移一位
void listRotate(list *list) {
listNode *tail = list->tail;
if (listLength(list) <= 1) return;
// 更新表尾
list->tail = tail->prev;
list->tail->next = NULL;
// 更新自身指標
tail->prev = NULL;
tail->next = list->head;
// 更新表頭
list->head->prev = tail;
list->head = tail;
}