概述
鏈表提供順序訪問方式,有高效的節點重排能力和節點增刪能力。
Redis由C語言實現, 但C語言沒有自帶鏈表的數據結構。因此Redis構建了自己的鏈表實現。
Redis應用廣泛, 例如列表鍵的底層實現之一就是鏈表。當一個列表建包含了數量較多的元素時,又或者列表中包含的元素都是比較長的字符串時, Redis就會使用鏈表作爲鏈表建的底層實現。
除鏈表建外,發佈與訂閱、慢查詢、監視器等功能也用到了鏈表, Redis服務器本身還是用鏈表來保存多個客戶端的狀態信息,以及使用鏈表構建客戶端輸出緩衝區
結構定義
鏈表節點的結構體(C語言)
typedef struct listNode{
// 前置節點
struct listNode *prev;
// 後置節點
struct listNode *next;
// 值
void *value;
}listNode;
用list鏈表來持有鏈表, 操作起來更爲方便
鏈表結構體:
typedef struct list{
// 鏈表頭結點
listNode *head;
// 鏈表尾節點
listNode *tail;
// 鏈表包含節點數
unsigned long len;
// 節點複製函數
void *(*dup)(void *ptr);
// 節點值釋放函數
void (*free)(void *prt);
// 節點值對比函數
void (*match)(void *ptr, void *key);
}list;
特性
- 雙向鏈表, 訪問一個節點的前一個節點或後一個節點的時間複雜度均爲O(1)
- 無環: 訪問到NULL即爲鏈表終點
- 帶頭指針和尾指針: 訪問鏈表兩端的時間複雜度爲O(1)
- 帶鏈表長度計數器: 獲得鏈表長度時間複雜度爲O(1)
- 多態:提供void *類型的value值可以複製任意類型數據, 且可以自行設置複製、釋放、比較等操作函數.
API
函數 | 作用 | 時間複雜度 |
listSetDupMethod | 將給定的函數設置爲鏈表的節點值複製函數 |
複製函數可以通過鏈表的dup |
listGetDupMethod | 返回鏈表當前正在使用的節點值複製函數 | O(1) |
listSetFreeMethod | 將給定的函數設置爲鏈表的節點值釋放函數 |
釋放函數可以通過鏈表的free |
listGetFree | 返回鏈表當前正在使用的節點值釋放函數 |
O(1) |
listSetMatchMethod | 將給定的函數設置爲鏈表的節點值對比函數 | 對比函數可以通過鏈表的match 屬性直接獲得,O(1) |
listGetMatchMethod | 返回鏈表當前正在使用的節點值對比函數 | O(1) |
listLength | 返回鏈表的長度(包含了多少個節點) |
鏈表長度可以通過鏈表的len |
listFirst | 返回鏈表的表頭節點 |
表頭節點可以通過鏈表的head |
listLast | 返回鏈表的表尾節點 |
表尾節點可以通過鏈表的tail |
listPrevNode | 返回給定節點的前置節點 |
前置節點可以通過節點的prev |
listNextNode | 返回給定節點的後置節點 |
後置節點可以通過節點的next |
listNodeValue | 返回給定節點目前正在保存的值 | 節點值可以通過節點的value屬性直接獲得,O(1) |
listCreate | 創建一個不包含任何節點的新鏈表 | O(1) |
listAddNodeHead |
將一個包含給定值的新節點添加到給定鏈表 |
O(1) |
listAddNodeTail |
將一個包含給定值的新節點添加到給定鏈表 |
O(1) |
listInsertNode |
將一個包含給定值的新節點添加到給定節點 |
O(1) |
listSearchKey | 查找並返回鏈表中包含給定值的節點 | O(N),N 爲鏈表長度 |
listIndex | 返回鏈表在給定索引上的節點 | O(N),N 爲鏈表長度 |
listDelNode | 從鏈表中刪除給定節點 | O(N),N 爲鏈表長度 |
listRotate |
將鏈表的表尾節點彈出,然後將被彈出的節 |
O(1) |
listDup | 複製一個給定鏈表的副本 | O(N),N 爲鏈表長度 |
listRelease | 釋放給定鏈表,以及鏈表中的所有節點 | O(N),N 爲鏈表長度 |
參考: 《redis設計與實現》