「Redis設(shè)計(jì)與實(shí)現(xiàn)」鏈表篇

鏈表簡(jiǎn)介

鏈表提供了高效的節(jié)點(diǎn)重排能力, 以及順序性的節(jié)點(diǎn)訪問(wèn)方式, 并且可以通過(guò)增刪節(jié)點(diǎn)來(lái)靈活地調(diào)整鏈表的長(zhǎng)度。作為一種常用數(shù)據(jù)結(jié)構(gòu), 鏈表內(nèi)置在很多高級(jí)的編程語(yǔ)言里面, 因?yàn)?Redis 使用的 C 語(yǔ)言并沒(méi)有內(nèi)置這種數(shù)據(jù)結(jié)構(gòu), 所以 Redis 構(gòu)建了自己的鏈表實(shí)現(xiàn)。

鏈表及鏈表節(jié)點(diǎn)的實(shí)現(xiàn)

  • 每個(gè)鏈表節(jié)點(diǎn)使用一個(gè)adlist.h/listNode結(jié)構(gòu)來(lái)表示
typedef struct listNode {
    struct listNode *prev; /* 前置節(jié)點(diǎn) */
    struct listNode *next; /* 后置節(jié)點(diǎn) */
    void *value; /* 節(jié)點(diǎn)值 */
} listNode;
  • Reids還定義了鏈表結(jié)構(gòu),用于持有鏈表
typedef struct list {
    listNode *head; /* 表頭結(jié)點(diǎn) */
    listNode *tail; /* 表尾結(jié)點(diǎn) */
    void *(*dup)(void *ptr); /* 節(jié)點(diǎn)復(fù)制函數(shù) */
    void (*free)(void *ptr); /* 節(jié)點(diǎn)釋放函數(shù) */
    int (*match)(void *ptr, void *key); 
    unsigned long len; /* 鏈表節(jié)點(diǎn)數(shù)量 */
} list;

list 結(jié)構(gòu)為鏈表提供了表頭指針 head 、表尾指針 tail , 以及鏈表長(zhǎng)度計(jì)數(shù)器 len , 而 dup 、 free 和 match 成員則是用于實(shí)現(xiàn)多態(tài)鏈表所需的類型特定函數(shù):

  1. dup 函數(shù)用于復(fù)制鏈表節(jié)點(diǎn)所保存的值;
  2. free 函數(shù)用于釋放鏈表節(jié)點(diǎn)所保存的值;
  3. match 函數(shù)則用于對(duì)比鏈表節(jié)點(diǎn)所保存的值和另一個(gè)輸入值是否相等。

如圖是由一個(gè)list結(jié)構(gòu)和三個(gè)listNode結(jié)構(gòu)組成的鏈表


list持有l(wèi)istNode示例.png

這樣定義好處是

  1. 快速獲取鏈表的頭尾
  2. 快速查詢鏈表的節(jié)點(diǎn)數(shù),像動(dòng)態(tài)字符串sdshr里的len那樣,不用遍歷全部字符就可以獲取字符串的長(zhǎng)度,這里也類似。
  • adlist.h/listIter還定義了迭代器
typedef struct listIter {
    listNode *next; /* 當(dāng)前迭代到的節(jié)點(diǎn) */
    int direction; /* 迭代方向 */
} listIter;
/* Directions for iterators 
 *
 * 迭代器進(jìn)行迭代的方向
 */
// 從表頭向表尾進(jìn)行迭代
#define AL_START_HEAD 0
// 從表尾到表頭進(jìn)行迭代
#define AL_START_TAIL 1

可以這樣迭代

iter = listGetIterator(list, AL_START_HEAD);
while ((node = listNext(iter)) != NULL) {
    doSomethingWith(node);
}

鏈表和鏈表節(jié)點(diǎn)的API

函數(shù) 作用 時(shí)間復(fù)雜度
listSetDupMethod 將給定的函數(shù)設(shè)置為鏈表的節(jié)點(diǎn)值復(fù)制函數(shù)。 O(1)
listGetDupMethod 返回鏈表當(dāng)前正在使用的節(jié)點(diǎn)值復(fù)制函數(shù)。 復(fù)制函數(shù)可以通過(guò)鏈表的 dup 屬性直接獲得, O(1)
listSetFreeMethod 將給定的函數(shù)設(shè)置為鏈表的節(jié)點(diǎn)值釋放函數(shù)。 O(1)
listGetFree 返回鏈表當(dāng)前正在使用的節(jié)點(diǎn)值釋放函數(shù)。 釋放函數(shù)可以通過(guò)鏈表的 free 屬性直接獲得, O(1)
listSetMatchMethod 將給定的函數(shù)設(shè)置為鏈表的節(jié)點(diǎn)值對(duì)比函數(shù)。 O(1)
listGetMatchMethod 返回鏈表當(dāng)前正在使用的節(jié)點(diǎn)值對(duì)比函數(shù)。 對(duì)比函數(shù)可以通過(guò)鏈表的 match 屬性直接獲得, O(1)
listLength 返回鏈表的長(zhǎng)度(包含了多少個(gè)節(jié)點(diǎn))。 鏈表長(zhǎng)度可以通過(guò)鏈表的 len 屬性直接獲得, O(1)
listFirst 返回鏈表的表頭節(jié)點(diǎn)。 表頭節(jié)點(diǎn)可以通過(guò)鏈表的 head 屬性直接獲得, O(1)
listLast 返回鏈表的表尾節(jié)點(diǎn)。 表尾節(jié)點(diǎn)可以通過(guò)鏈表的 tail 屬性直接獲得, O(1)
listPrevNode 返回給定節(jié)點(diǎn)的前置節(jié)點(diǎn)。 前置節(jié)點(diǎn)可以通過(guò)節(jié)點(diǎn)的 prev 屬性直接獲得, O(1)
listNextNode 返回給定節(jié)點(diǎn)的后置節(jié)點(diǎn)。 后置節(jié)點(diǎn)可以通過(guò)節(jié)點(diǎn)的 next 屬性直接獲得, O(1)
listNodeValue 返回給定節(jié)點(diǎn)目前正在保存的值。 節(jié)點(diǎn)值可以通過(guò)節(jié)點(diǎn)的 value 屬性直接獲得, O(1)
listCreate 創(chuàng)建一個(gè)不包含任何節(jié)點(diǎn)的新鏈表。 O(1)
listAddNodeHead 將一個(gè)包含給定值的新節(jié)點(diǎn)添加到給定鏈表的表頭。 O(1)
listAddNodeTail 將一個(gè)包含給定值的新節(jié)點(diǎn)添加到給定鏈表的表尾。 O(1)
listInsertNode 將一個(gè)包含給定值的新節(jié)點(diǎn)添加到給定節(jié)點(diǎn)的之前或者之后。 O(1)
listSearchKey 查找并返回鏈表中包含給定值的節(jié)點(diǎn)。 O(N) , N 為鏈表長(zhǎng)度
listIndex 返回鏈表在給定索引上的節(jié)點(diǎn)。 O(N) , N 為鏈表長(zhǎng)度
listDelNode 從鏈表中刪除給定節(jié)點(diǎn)。 O(1)
listRotate 將鏈表的表尾節(jié)點(diǎn)彈出,然后將被彈出的節(jié)點(diǎn)插入到鏈表的表頭, 成為新的表頭節(jié)點(diǎn)。 O(1)
listDup 復(fù)制一個(gè)給定鏈表的副本。 O(N) , N 為鏈表長(zhǎng)度
listRelease 釋放給定鏈表,以及鏈表中的所有節(jié)點(diǎn)。 O(N) , N 為鏈表長(zhǎng)度
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容