1. 程式人生 > >redis 系列4 資料結構之連結串列

redis 系列4 資料結構之連結串列

一. 概述

  連結串列提供了高效的節點重排能力,以及順序性的節點訪問方式,並且可能通過增刪節點來靈活地調整連結串列的長度。作為一種資料結構,在C語言中並沒有內建的這種資料結構。所以Redis構建了自己的連結串列實現。連結串列在Redis中應用非常多,比如列表鍵的底層實現之一就是連結串列,當一個列表鍵包含了數量比較多的元素,又或者列表中包含的元素都是比較長的字串時,Redis就會使用連結串列作為列表鍵的底層實現。

-- 例1:使用integers 列表鍵包含了從1到10,共有10個整數
127.0.0.1:6379> rpush integers "1" "2" "3" "4" "5" "6"
"7" "8" "9" "10" (integer) 10 127.0.0.1:6379> llen integers (integer) 10 127.0.0.1:6379> lrange integers 0 5 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6"

  integers列表鍵的底層實現就是一個連結串列。連結串列中的每個節點都儲存了一個整數值,除了連結串列鍵之外,釋出與訂閱,慢查詢,監視器等功能也用到了連結串列。Redis伺服器本身還使用連結串列來儲存多個客戶端的狀態資訊,以及使用連結串列來構建客戶端輸出緩衝區(output buffer)。

二 連結串列和連結串列節點定義

// 每個連結串列節點使用一個adlist.h/listNode結構來表示:
      typedef struct listNode
        {
            //前置節點
            struct listNode *prev;
            //後置節點
            struct listNode *next;
            //節點的值
            void *value;
        }listNode; //別名

  多個listNode可能通過prev和next指標組成雙端連結串列。雖然使用多個listNode結構就可以組成連結串列,但使用adlist.h/list 來持有連結串列的話,操作起來會更方便。

 typedef struct list
        {
            //表頭節點
            listNode    *head;
            //表尾節點
             listNode *tail;
            //連結串列所包含的節點數量 
            unsigned long len;
            //節點值複製函式
            void *(*dup) (void *ptr);
            //節點值釋放函式
            void (*free)(void *ptr)
            //節點值對比函式
            int (*match) (void *ptr,void *key)
        }list; //別名

  在list結構中連結串列提供了表頭指標head, 表尾指標tail,以及連結串列長度計數器len, 而dup, free和match成員則是用於實現多型連結串列所需的型別特定函式:dup 函式用於複製連結串列節點所儲存的值; free 函式用於釋放連結串列節點所儲存的值; match 函式則用於對比連結串列節點所儲存的值和另一個輸入值是否相等。

三.Redis的連結串列實現的特性總結

  (1)雙端: 連結串列節點帶有prev 和next 指標,獲取某個節點的前置節點和後置節點的複雜度都是0(1) 。

  (2)無環: 表頭節點的prev指標和表尾節點的next 指標都指向null ,對連結串列的訪問以null 為終點 。

  (3)帶表頭指標和表尾指標:通過list結構的head指標和tail 指標,程式獲取連結的表頭節點和表尾節點的複雜度為0(1)

  (4)帶連結串列長度計數器:程式使用list結構的len屬性來對list持有的連結串列節點進行計數,程式獲取連結串列中節點數量的複雜度為0(1)

  (5)多型:連結串列節點使用void* 指標來儲存節點值,並且可能通過list結構的dup,free,match 三個屬性為節點值設定型別特定函式,所以連結串列可以用於儲存各種不同型別的值。

四. 連結串列和連結串列節點的API

函式

作用

listSetDupMethod

將給定的函式設定為連結串列的節點值複製函式

listGetDupMethod

返回連結串列當前正在使用的節點值複製函式

listSetFreeMethod

將給定的函式設定為連結串列的節點值釋放函式

listGetFree

返回連結串列當前正在使用的節點值釋放函式

listSetMatchMethod

將給定的函式設定為連結串列的節點值對比函式

listGetMatchMethod

返回連結串列當前正在使用的節點值對比函式

listLenth

返回連結串列的長度(包含多少節點)

listFirst

返回連結串列的表頭節點

listLast

返回連結串列的表尾節點

listPrevNode

返回給定節點的前置節點

listNextNode

返回給定節點的後置節點

listNodeValue

返回給定節點目前正在儲存的值

listCreate

建立一個不包含任何節點的新連結串列

listAddNodeHead

將一個包含給定值的新節點新增到給定連結串列的表頭

listAddNodeTail

將一個包含給定值的新節點新增到給定連結串列的表尾

listInsertNode

將一個包含給定值的新節點新增到給定節點的之前或者之後

listSearchKey

查詢並返回連結串列中包含給定值的節點

listIndex

返回連結串列在給定索引上的節點

listDelNode

從連結串列中刪除給定節點

listRotate

將連結串列的表尾節點彈出,然後將被彈出的節點插入到連結串列的表頭,成為新的表頭節點

listDup

複製一個給定連結串列的副本

listRelease

釋放給定連結串列,以及連結串列中的所有節點

  總結:

    (1) 連結串列被廣泛用於實現Redis的各種功能,比如列表鍵,釋出與訂閱,慢查詢,監視器等。

    (2) 每個連結串列節點由一個listNode結構來表示,每個節點都有一個指定前置節點和後置節點的指標,所以Redis的連結串列實現是雙端連結串列。

    (3) 每個連結串列使用一個list結構來表示,這個結構帶有表頭節點指標 ,表尾節點指標,以及連結串列長度等資訊。

    (4) 因為連結串列表頭節點的前置節點和表尾節點的後置節點都指向null, 所以Redis的連結串列實現是無環連結串列。

    (5) 通過為連結串列設定不同的型別特定函式,Redis的連結串列可以用於儲存各種不同型別的值。