深入理解Redis 資料結構—雙連結串列

小碼code發表於2021-11-30

在 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節點

多個 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設計與實現

如果覺得文章對你有幫助的話,請點個推薦吧!

相關文章