前言
鏈表提供了高效的節點重排能力,以及順序性的節點訪問方式,鏈表在 Redis 中的應用很廣泛,比如列表鍵的底層實現之一就是鏈表,除此之外,發佈與訂閱、慢查詢、監視器等功能也用到了鏈表,Redis 服務器本身使用鏈表保存多個客戶端的狀態信息,使用鏈表構建客戶端輸出緩衝區。
鏈表的底層實現
學習過算法的同學都知道數據結構中的鏈表的相關概念了,這裏簡單介紹一下鏈表的數據結構:
鏈表是常見的基礎數據結構,是一種線性表,但是並不會按線性的順序存儲數據,而是在每一個節點裏存到下一個節點的指針(Pointer)。由於不必須按順序存儲,鏈表在插入的時候可以達到O(1)的複雜度,比另一種線性表 順序錶快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而順序表相應的時間複雜度分別是O(logn)和O(1)。(來源於維基百科)
先來看看一個鏈表節點的數據結構:
typedef struct listNode {
// 前置節點
struct listNode *prev;
// 後置節點
struct listNode *next;
// 節點的值
void *value;
}listNode;
多個 listNode (鏈表節點)通過 prev 和 next 指針組成雙向鏈表
下面使用 list 數據結構來管理鏈表:
typedef struct list {
// 表頭節點
listNode *head;
// 表尾節點
listNode *tail;
// 鏈表所包含的節點數量
unsigned long len;
// 節點值複製函數
void *(*dup)(void *ptr);
// 節點值釋放函數
void *(*free)(void *ptr);
// 節點值對比函數
void *(*match)(void *ptr, void *key);
}list;
list 結構爲鏈表提供了表頭指針head, 表尾指針tail,以及鏈表長度計數器len, 而dup、free 和match 函數的作用如下:
- dup 函數用於複製鏈表節點所保存的值
- free 函數用於釋放鏈表節點所保存的值
- match 函數用於對比鏈表節點所保存的值與另外一個輸入值是否相等
list 結構與 listNode 結構組成的鏈表
Redis 鏈表特點總結
- 雙向: 鏈表節點都有 prev 和 next 指針,可以獲取某個節點的前置節點和後置節點,複雜度爲O(1)
- 無環:上面圖片顯示,表頭節點的 prev 指針和表尾節點的 next 指針都指向 NULL
- 帶表頭指針和表尾指針: 通過 list 結構的 head 和 tail 指針,獲取表頭節點和表尾節點的複雜度爲O(1)
- 帶鏈表長度計數器:通過 list 結構的 len 字段記錄了 鏈表中的鏈表節點(listNode)數,獲取鏈表長度的複雜度爲O(1)
- 多態:鏈表節點使用 void * 指針來保存節點值,可以通過 list 結構的 dup、free和match 屬性爲節點值設置類型特定函數,所有鏈表可用於保存不同類型的值
這章內容比較少,基本就是 Redis 設計與實現 原樣搬過來的,很容易瞭解,講的特別好,主要是做個記錄,以後可以翻閱。