在 Redis 資料型別中的列表list,對資料的新增和刪除常用的命令有 lpush,rpush,lpop,rpop,其中 l 表示在左側,r 表示在右側,可以在左右兩側做新增和刪除操作,說明這是一個雙向的資料結構,而 list 資料結構正是雙向連結串列,類似 java 中的 LinekdList 連結串列列表。
連結串列提供了高效的節點重排能力,以及順序的節點訪問方式,通過修改節點的 pre 和 next 指標來修改連結串列的資料。
C 語言沒有內建連結串列的資料結構,所以 Redis 構建了自己的連結串列結構。
連結串列的資料結構,連結串列以及連結串列節點
連結串列是由連結串列以及連結串列節點組成,每個連結串列節點使用一個 adlist.h/listNode 結構來表示:
typedef struct listNode {
//前置節點
struct listNode *prev;
//後置節點
struct listNode *next;
// 節點值
void *value;
} listNode;
多個 listNode 可以通過 prev 和 next 指標組成雙連結串列的,如題所示:
多個 listNode 可以組成連結串列,但是為了方便管理,使用 adlist.h/list 管理連結串列,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;
list 結構為連結串列提供了表頭指標 head、表尾指標 tail,以及節點數量計算 len。下圖展示一個由 list 結構和三個 listNode 節點組成的連結串列:
Redis 連結串列實現的特徵有如下的總結:
- 雙向:連結串列節點帶有 prev 和 next 指標,可以通過指標獲取每一個資料
- 快速計算連結串列長度:通過 list 結構中的 len 屬性計算 list 的長度,而時間複雜度為O(1)
- 多型: 連結串列節點使用 void* 指標儲存節點,所以連結串列支援儲存各種不同型別的值
雙連結串列的運用
列表鍵,釋出訂閱、慢查詢以及監視器等。
總結
- 本文通過介紹連結串列的資料結構,連結串列是由連結串列和連結串列節點組成的
- 連結串列節點都有一個前置和後置指標,所以 Redis 的連結串列是一個雙向連結串列
- 連結串列可以儲存頭結點,尾節點,更好的管理自己的節點,len 屬性快速算出連結串列的長度
- 連結串列通過 void* 以及不同的型別設定函式,所以連結串列可以不同的型別的值
參考
- Redis設計與實現
如果覺得文章對你有幫助的話,請點個推薦吧!