Redis中是本身實現的鏈表。鏈表被普遍用於Redis的各類功能,好比列表鍵、發佈於訂閱、慢查詢、監視器等。node
列表鍵的底層實現之一就是鏈表(Redis3.2 以前,在Redis3.2 後被換成了快速列表quicklist
)。當一個列表建包含了數量比較多的元素,又或者列表中包含的元素都是比較長的字符串時,Reids會使用鏈表做爲列表鍵的底層實現。(《Redis設計與實現》)函數
來之《Redis設計與實現》ui
listNode
結構來表示,每一個結點都由一個指向前置結點和後置結點的指針,全部Redis的鏈表實現是雙端鏈表。list
結構來表示,這個結構帶有表頭結點指針、表位結點指針、已經鏈表長度等信息。// adlist.h // 鏈表結點 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; // 鏈表的迭代器 typedef struct listIter { listNode *next; // 下一個節點 int direction; // 迭代方向 } listIter;
dup
函數用於複製鏈表節點所保存的值;free
函數用於釋放鏈表節點所保存的值;match
函數用於對比鏈表節點所保存的值和另外一個輸入值是否相等;list *listAddNodeHead(list *list, void *value)
向list中添加鏈表頭:設計
/* Add a new node to the list, to head, containing the specified 'value' * pointer as value. * * On error, NULL is returned and no operation is performed (i.e. the * list remains unaltered). * On success the 'list' pointer you pass to the function is returned. */ list *listAddNodeHead(list *list, void *value) { listNode *node; // 爲鏈表節點分配內存 if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; // 給鏈表節點的value賦值 node->value = value; if (list->len == 0) { // 若是list原本沒有節點,則將表頭節點和表尾節點都設置node list->head = list->tail = node; // 且node的前置和後置節點都是NULL node->prev = node->next = NULL; } else { // 若是list原本已經存在節點 // 則將node的前置節點設爲NULL node->prev = NULL; // 而後將node的後置節點指向list本來的表頭節點 node->next = list->head; // 將list本來的表頭節點的前置節點指向node list->head->prev = node; // 將node設爲list的新表頭節點 list->head = node; } // list的長度加1 list->len++; return list; }
list *listInsertNode(list *list, listNode *old_node, void *value, int after)
向list中插入節點value
,插入位置是old_node
,after
表示在old_node
前仍是後:指針
list *listInsertNode(list *list, listNode *old_node, void *value, int after) { listNode *node; // 給要插入的節點node分配內存 if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; // node的value賦值 node->value = value; if (after) { // 插入到old_node後 node->prev = old_node; node->next = old_node->next; if (list->tail == old_node) { // 若是old_node本來是表尾節點,則從新將表尾節點指向node list->tail = node; } } else { // 插入到old_node前 node->next = old_node; node->prev = old_node->prev; if (list->head == old_node) { // 若是old_node本來是表頭節點,則從新將表尾節點指向node list->head = node; } } if (node->prev != NULL) { //若是node的前置節點不爲NULL,則將node的前置節點的後置節點指向node node->prev->next = node; } if (node->next != NULL) { //若是node的後置節點不爲NULL,則將node的後置節點的前置節點指向node node->next->prev = node; } // list的長度加1 list->len++; return list; }
void listDelNode(list *list, listNode *node)
刪除list中的節點node
:code
/* Remove the specified node from the specified list. * It's up to the caller to free the private value of the node. * * This function can't fail. */ void listDelNode(list *list, listNode *node) { if (node->prev) // 若是node有前置節點 // 則將 node前置節點的後置節點 指向 node的後置節點 node->prev->next = node->next; else // 若是node沒有前置節點,則說明node是表頭節點 // 將list的表頭節點指向 node的後置節點 list->head = node->next; if (node->next) // 若是node有後置節點 // 則將 node的後置節點的前置節點 指向 node的前置節點 node->next->prev = node->prev; else // 若是node沒有後置節點,則說明node是表尾節點 // 將list的表尾節點指向 node的前置節點 list->tail = node->prev; // 若是list有free函數,則調用free函數釋放node中的value if (list->free) list->free(node->value); // 釋放node的內存 zfree(node); // list長度減1 list->len--; }
參考之《Redis設計與實現》orm
函數 | 做用 | 時間複雜度 |
---|---|---|
list *listCreate(void) |
建立一個不包含任何節點的新鏈表 | O(1) |
void listRelease(list *list) |
釋放整個鏈表 | O(N) |
void listEmpty(list *list) |
將整個鏈表的節點狀況,不釋放鏈表自己 | O(N) |
list *listAddNodeHead(list *list, void *value) |
將一個包含給定值的新節點添加爲鏈表的表頭 | O(1) |
list *listAddNodeTail(list *list, void *value) |
將一個包含給定值的新節點添加爲鏈表的表尾 | O(1) |
list *listInsertNode(list *list, listNode *old_node, void *value, int after) |
將一個包含給定值的新節點添加到鏈表給定節點的前或者後 | O(1) |
void listDelNode(list *list, listNode *node) |
刪除鏈表中的給定節點 | O(1) |
listIter *listGetIterator(list *list, int direction) |
獲取給定鏈表的迭代器 | O(1) |
listNode *listNext(listIter *iter) |
獲取鏈表迭代器的下一個節點 | O(1) |
void listReleaseIterator(listIter *iter) |
釋放鏈表迭代器 | O(1) |
list *listDup(list *orig) |
複製一個給定鏈表的副本 | O(N) |
listNode *listSearchKey(list *list, void *key) |
在給定鏈表中查找並返回鏈表中包含給定值key 的節點 |
O(N) |
listNode *listIndex(list *list, long index) |
返回鏈表中給定索引index 上的節點 |
O(N) |
void listRewind(list *list, listIter *li) |
將給定迭代器li 指定給定的鏈表list ,迭代器li 指向的是鏈表list 的表頭結點 |
O(1) |
void listRewindTail(list *list, listIter *li) |
將給定迭代器li 指定給定的鏈表list ,但迭代器li 指向的是鏈表list 的表尾結點 |
O(1) |
void listRotate(list *list) |
將鏈表的尾結點彈出,而後將被彈出的節點插入到鏈表的表頭,成爲新的表頭節點 | O(1) |
void listJoin(list *l, list *o) |
將鏈表o 的節點追加到鏈表l 的表尾後,而後將o 設置爲空(不是NULL,而是沒有節點) |
O(1) |