Redis的資料結構(二):連結串列
連結串列在redis的應用
由於redis的c語言沒有內建連結串列結構型別,因此redis自身實現了一套連結串列結構。連結串列主要應用在幾個方面:
- 應用於較長的list結構中
- 釋出與訂閱
- 監視器
- 儲存多個客戶端狀態資訊等等
連結串列在redis中的實現
我們翻到原始碼 src/adlist.h
中的 listNode
結構體,這個結構體也就是連結串列節點的實現:
/* * 雙端連結串列節點 */ typedef struct listNode { // 前置節點 struct listNode *prev; // 後置節點 struct listNode *next; // 節點的值 void *value; } listNode;
可以看到,如果畫成圖,那麼多個 listNode
就會變成這樣的一個連結串列:

image.png
list
,原始碼位於
src/adlist.h
的
list
結構體:
/* * 雙端連結串列結構 */ 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;
其中,比較難看懂的應該就是 dup
、 free
、 match
三個欄位,我們分別解釋一下這三個欄位的作用:
-
dup
:主要是用來複制連結串列節點所儲存的值 -
free
:主要是用來釋放連結串列節點的記憶體空間 -
match
:用來比對節點值,通常用來查詢某個值是否在連結串列中
那麼,為什麼要抽出這三個成獨立的欄位呢?答案就是為了多型,我們都知道void*
在C語言是表示任意型別的指標,加上鍊表節點的value
也是用void*
儲存的,因此通過dup
、free
、match
三個欄位函式就可以操作各種型別的值,也讓連結串列節點能夠儲存任何型別的值了。
redis中連結串列的特性總結
總體來說,redis的連結串列結構非常簡單高效,主要體現以下幾方面:
- 雙端連結串列。每個連結串列節點
listNode
都包含了prev
和next
欄位,用來指向該節點前一個節點和後一個節點,這樣可以使得節點查詢前一個和後一個節點的計算複雜度變為O(1)。 - 無環。
listNode
的prev
和next
欄位都是指向NULL,因此連結串列是無環的。 - 帶表頭的表尾指標。連結串列
list
帶有head
和tail
指標,使得查詢連結串列的表頭和表尾節點的計算複雜度變為O(1)。 - 連結串列長度計算器。連結串列
list
有一個欄位len
,使得計算連結串列長度的複雜度變為O(1),而不用通過遍歷連結串列來獲取總長度。