国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

從 Redis 源碼了解雙向鏈表的設(shè)計(jì)與實(shí)現(xiàn)

數(shù)據(jù)庫(kù) Redis
本文我們將redis底層的雙向鏈表的設(shè)計(jì)與實(shí)現(xiàn)的源碼進(jìn)行的深入分析,從中了解到redis雙向鏈表數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)和節(jié)點(diǎn)操作的實(shí)現(xiàn)細(xì)節(jié)

近期一直嘗試用go語(yǔ)言復(fù)刻redis,所以開(kāi)始深入研究redis那些巧妙的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)與實(shí)現(xiàn),本篇文章將針對(duì)redis中鏈表的設(shè)計(jì)與實(shí)現(xiàn)進(jìn)行源碼級(jí)別的分析,希望對(duì)你有所啟發(fā)。

詳解redis中鏈表的設(shè)計(jì)與實(shí)現(xiàn)

鏈表底層結(jié)構(gòu)的設(shè)計(jì)

鏈表是由無(wú)數(shù)個(gè)節(jié)點(diǎn)也就是我們常說(shuō)的listNode構(gòu)成,每個(gè)節(jié)點(diǎn)通過(guò)前驅(qū)和后繼節(jié)點(diǎn)指針維護(hù)其前驅(qū)和后繼節(jié)點(diǎn)信息:

對(duì)應(yīng)的我們也給出redis中鏈表節(jié)點(diǎn)listNode 的源碼,它位于adlist.h的定義中,可以看到它通過(guò)prev指針和next指針?lè)謩e管理當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)和后繼節(jié)點(diǎn),然后通過(guò)value指針維護(hù)當(dāng)前節(jié)點(diǎn)的值,由這一個(gè)個(gè)節(jié)點(diǎn)的串聯(lián)構(gòu)成雙向鏈表:

typedef struct listNode {
    //指向前驅(qū)節(jié)點(diǎn)
    struct listNode *prev;
    //指向后繼節(jié)點(diǎn)
    struct listNode *next;
    //維護(hù)當(dāng)前節(jié)點(diǎn)的值的指針
    void *value;
} listNode;

雙向鏈表需要一個(gè)頭指針和尾指針管理首尾節(jié)點(diǎn),從而實(shí)現(xiàn)后續(xù)靈活的頭插法和尾插法的操作,所以在設(shè)計(jì)雙向鏈表的時(shí)候,我們就需要一個(gè)head和tail指針管理鏈表的首尾節(jié)點(diǎn)。同時(shí),為了實(shí)現(xiàn)O(1)級(jí)別的長(zhǎng)度計(jì)算,在元素添加或者刪除操作的時(shí)候,我們還需要一個(gè)len字段記錄當(dāng)前鏈表的長(zhǎng)度:

而redis中雙向鏈表的結(jié)構(gòu)體list 也是同理:

typedef struct list {
    //頭節(jié)點(diǎn)指針
    listNode *head;
    //尾節(jié)點(diǎn)指針
    listNode *tail;
    //......
    //鏈表長(zhǎng)度
    unsigned long len;
} list;

了解了基本的數(shù)據(jù)結(jié)構(gòu),我們?cè)賮?lái)說(shuō)說(shuō)鏈表的初始化,redis中的雙向鏈表會(huì)為其分配一塊內(nèi)存空間,然后將頭尾節(jié)點(diǎn)的指針設(shè)置為空,長(zhǎng)度初始化為0:

對(duì)應(yīng)的我們給出雙向鏈表初始化的源碼即位于adlist.c的listCreate函數(shù),它完成空間分配和指針、長(zhǎng)度初始化之后返回這個(gè)鏈表的指針:

list *listCreate(void)
{
    //為list結(jié)構(gòu)體分配內(nèi)存空間
    struct list *list;

    if ((list = zmalloc(sizeof(*list))) == NULL)
        return NULL;
    //頭尾指針初始化設(shè)置為空    
    list->head = list->tail = NULL;
    //鏈表長(zhǎng)度設(shè)置為0
    list->len = 0;
   //......
    return list;
}

節(jié)點(diǎn)頭插法的實(shí)現(xiàn)

通過(guò)上文我們了解了鏈表的基本數(shù)據(jù)結(jié)構(gòu),接下來(lái)我們就來(lái)聊聊鏈表的第一個(gè)操作,也就是頭插法,這個(gè)操作就是將最新的節(jié)點(diǎn)插入的鏈表的首部,我們以初次插入為例,此時(shí)鏈表全空,雙向鏈表初始化節(jié)點(diǎn)之后,就會(huì)讓鏈表的頭尾指針指向這個(gè)node,然后長(zhǎng)度自增為1:

若非第一次操作,則初始化一個(gè)新節(jié)點(diǎn)之后,讓這個(gè)節(jié)點(diǎn)指向原有的頭節(jié)點(diǎn),最后讓原有的頭節(jié)點(diǎn)作為新節(jié)點(diǎn)的后繼即可:

圖片圖片

對(duì)此我們也給出頭插法的源碼,可以看到它會(huì)傳入當(dāng)前需要操作的鏈表和新節(jié)點(diǎn)的value指針完成節(jié)點(diǎn)生成和頭插工序,對(duì)應(yīng)的源碼操作細(xì)節(jié)和上述講解大體一致,讀者可自行參閱:

list *listAddNodeHead(list *list, void *value)
{
    //初始化node節(jié)點(diǎn)內(nèi)存空間
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    //value指針指向傳入的值    
    node->value = value;
    //如果鏈表長(zhǎng)度為0,則讓首尾節(jié)點(diǎn)指向這個(gè)node,然后node前驅(qū)和后繼節(jié)點(diǎn)為空
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        //節(jié)點(diǎn)的前驅(qū)指向空,后繼節(jié)點(diǎn)指向原有的頭節(jié)點(diǎn),完成后再讓原有的頭節(jié)點(diǎn)作為新節(jié)點(diǎn)的后繼節(jié)點(diǎn)
        //最后head指針指向當(dāng)前node
        node->prev = NULL;
        node->next = list->head;
        list->head->prev = node;
        list->head = node;
    }
    //維護(hù)一下鏈表的長(zhǎng)度+1
    list->len++;
    return list;
}

尾插法的實(shí)現(xiàn)

尾插法就是將最新節(jié)點(diǎn)插入到鏈表末尾,初次插入和頭插法一致,即頭指針head和尾指針tail都指向最新node節(jié)點(diǎn),這里就不做贅述。 我們重點(diǎn)說(shuō)說(shuō)常規(guī)操作的尾插法,雙向鏈表在進(jìn)行尾插法時(shí)步驟如下:

  • 新節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)指向原有尾節(jié)點(diǎn)。
  • 原有的尾節(jié)點(diǎn)后繼指針指向新節(jié)點(diǎn)。
  • 修改tail指針指向,讓新節(jié)點(diǎn)作為最新的尾節(jié)點(diǎn)。

尾插法的函數(shù)為listAddNodeTail,入?yún)橐M(jìn)行操作的list指針和value值,操作步驟的上圖表述基本一致,讀者可結(jié)合注釋自行參閱:

list *listAddNodeTail(list *list, void *value)
{
    
    listNode *node;
    //分配node內(nèi)存空間
    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    //node的value指針指向value    
    node->value = value;
    //如果長(zhǎng)度為0,則首尾指針指向這個(gè)node
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        //新節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)指向尾節(jié)點(diǎn),然后讓原有尾節(jié)點(diǎn)指向新節(jié)點(diǎn),最后讓tail指針指向新節(jié)點(diǎn)
        node->prev = list->tail;
        node->next = NULL;
        list->tail->next = node;
        list->tail = node;
    }
    //長(zhǎng)度信息維護(hù)一下
    list->len++;
    return list;
}

指定節(jié)點(diǎn)插入

該函數(shù)會(huì)傳入修改前驅(qū)后繼關(guān)系的節(jié)點(diǎn),如果希望將新節(jié)點(diǎn)n插入到舊節(jié)點(diǎn)后面,則會(huì)讓新節(jié)點(diǎn)n的前驅(qū)指向原有節(jié)點(diǎn),后繼節(jié)點(diǎn)指向原有節(jié)點(diǎn)的后繼,最后讓新節(jié)點(diǎn)的前驅(qū)后繼節(jié)點(diǎn)指向插入的新節(jié)點(diǎn)n:

同理插入前面也很節(jié)點(diǎn)后添加差不多,這里就不多贅述,對(duì)此我們給出listInsertNode的源碼,可以看到它傳入需要進(jìn)行操作的list指針,再傳入需要維護(hù)新關(guān)系的old_node指針和需要插入的value,將value封裝為node之后,如果after為1則執(zhí)行上述所說(shuō)的old_node后節(jié)點(diǎn)插入操作:

  • node的前驅(qū)指向old_node。
  • node后繼指向old_node的后繼。
  • old_node的next指針和old_node的后繼節(jié)點(diǎn)都指向node。

對(duì)應(yīng)的源碼如下,讀者可參考筆者上述圖解并結(jié)合源碼注釋了解整個(gè)插入過(guò)程:

list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
    listNode *node;
    //節(jié)點(diǎn)初始化并設(shè)置value
    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    node->value = value;
    //如果after為1則將新節(jié)點(diǎn)插入到old_node后面
    if (after) {
        //node前驅(qū)指向old_node,node指向old_node的后繼
        node->prev = old_node;
        node->next = old_node->next;
        //如果old_node是尾節(jié)點(diǎn),則讓tail指向新插入的node
        if (list->tail == old_node) {
            list->tail = node;
        }
    } else {
        //將新節(jié)點(diǎn)插入到old_node前面
        node->next = old_node;
        node->prev = old_node->prev;
        //如果old_node是頭節(jié)點(diǎn),則修改head指向,讓其指向新節(jié)點(diǎn)
        if (list->head == old_node) {
            list->head = node;
        }
    }
    //將node原有的前驅(qū)后繼節(jié)點(diǎn)指向當(dāng)前node維護(hù)的前驅(qū)和后繼節(jié)點(diǎn)
    if (node->prev != NULL) {
        node->prev->next = node;
    }
    if (node->next != NULL) {
        node->next->prev = node;
    }
    //維護(hù)一下長(zhǎng)度
    list->len++;
    return list;
}

獲取指定位置的元素

雙向鏈表支持基于索引查找指定位置的元素,操作時(shí)間復(fù)雜度為O(n),我們以從頭查找為例,如果希望查找索引2的元素,也就是第3個(gè)元素,它就會(huì)從head開(kāi)始跳越2條,由此走到第3個(gè)節(jié)點(diǎn)的位置并返回這個(gè)節(jié)點(diǎn)的指針:

對(duì)應(yīng)我們給出listIndex的源碼,可以看到如果傳入的index為負(fù)數(shù),則說(shuō)明調(diào)用者要從后往前找,假設(shè)我們傳入-2也就是要找到倒數(shù)第2個(gè)元素,最終取正計(jì)算得到1,這也就意味著我們只需從尾節(jié)點(diǎn)跳1下就能得到倒數(shù)第2個(gè)元素,而index若為正數(shù)則是順序查找,原理如上圖解析,這里就不多贅述了,讀者可自行查閱listIndex函數(shù)及其源碼:

listNode *listIndex(list *list, long index) {
    listNode *n;
    //如果小于0,說(shuō)明從后往前照
    if (index < 0) {
        //將負(fù)數(shù)轉(zhuǎn)為正數(shù),例如傳入-2,也就找倒數(shù)第2個(gè)元素,轉(zhuǎn)為正為1,也就是往前1跳,返回這個(gè)node
        index = (-index)-1;
        n = list->tail;
        while(index-- && n) n = n->prev;
    } else {
        //說(shuō)明從前往后照,跳n跳即可得到對(duì)應(yīng)元素
        n = list->head;
        while(index-- && n) n = n->next;
    }
    return n;
}

刪除指定位置的元素

最后一個(gè)就是鏈表刪除操作了,操作比較簡(jiǎn)單,讓被刪除節(jié)點(diǎn)的前驅(qū)和后繼節(jié)點(diǎn)構(gòu)成關(guān)聯(lián)關(guān)系,然后釋放當(dāng)前被刪節(jié)點(diǎn),然后減小一下長(zhǎng)度即可:

對(duì)應(yīng)的源碼如下,讀者可自行參閱學(xué)習(xí):

void listDelNode(list *list, listNode *node)
{
    //如果node前驅(qū)有節(jié)點(diǎn),則讓這個(gè)節(jié)點(diǎn)指向被刪除節(jié)點(diǎn)的后繼
    //反之說(shuō)明這個(gè)節(jié)點(diǎn)是頭節(jié)點(diǎn),則讓head指向這個(gè)后繼節(jié)點(diǎn)
    if (node->prev)
        node->prev->next = node->next;
    else
        list->head = node->next;
    //如果這個(gè)節(jié)點(diǎn)有后繼節(jié)點(diǎn),則讓這個(gè)后繼的prev指向被刪節(jié)點(diǎn)的前驅(qū)
    //反之說(shuō)明被刪的是尾節(jié)點(diǎn),則讓tail指針指向被刪節(jié)點(diǎn)的后繼
    if (node->next)
        node->next->prev = node->prev;
    else
        list->tail = node->prev;
    //釋放被刪除節(jié)點(diǎn)的內(nèi)存空間,并減小鏈表長(zhǎng)度    
    if (list->free) list->free(node->value);
    zfree(node);
    list->len--;
}

小結(jié)

自此我們將redis底層的雙向鏈表的設(shè)計(jì)與實(shí)現(xiàn)的源碼進(jìn)行的深入分析,從中了解到redis雙向鏈表數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)和節(jié)點(diǎn)操作的實(shí)現(xiàn)細(xì)節(jié),希望對(duì)你有所幫助。

責(zé)任編輯:趙寧寧 來(lái)源: 寫(xiě)代碼的SharkChili
相關(guān)推薦

2021-05-07 08:20:52

前端開(kāi)發(fā)技術(shù)熱點(diǎn)

2024-11-22 15:00:00

開(kāi)源Redis鏈表

2024-04-26 00:02:00

Rust語(yǔ)言LinkedList

2020-07-01 08:07:33

Redis

2022-04-06 08:49:44

SSTKV存儲(chǔ)引擎

2010-02-26 13:14:39

Java日志系統(tǒng)

2022-12-26 00:51:33

雙向鏈表二叉搜索樹(shù)

2023-12-01 09:14:58

ReactFiber

2021-01-22 09:47:22

鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)

2025-05-22 08:15:00

2025-02-25 09:29:34

2025-03-20 09:54:47

2023-10-17 17:13:14

內(nèi)存程序源碼

2024-12-13 16:28:43

2025-01-06 08:10:00

Redis跳表索引

2021-03-10 08:20:54

設(shè)計(jì)模式OkHttp

2022-10-08 08:01:17

Spring源碼服務(wù)

2025-03-14 12:30:00

Redis RDBRedis數(shù)據(jù)庫(kù)

2020-02-07 11:07:53

數(shù)組鏈表單鏈表

2017-12-26 16:24:36

接口代碼數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

国产精品午夜电影| 美女欧美视频在线观看免费| 玖玖在线播放| 高清av一区二区| 国产精品美女久久久久久免费| 四虎在线观看| 91免费观看视频在线| 欧美一区1区三区3区公司| y111111国产精品久久久| 91麻豆精品一区二区三区| 日韩一区二区电影网| 国产精品videossex国产高清| 天天做夜夜做人人爱精品| 亚洲电影在线观看| 97超碰国产一区二区三区| 国产色产综合产在线视频| 亚洲一区二区三| 免费看一区二区三区| 欧美在线小视频| 欧美中文字幕在线| 欧美新色视频| 亚洲桃色在线一区| 欧美 日韩 激情| 精久久久久久久久久久| 欧美视频小说| 欧美国产日韩精品免费观看| 国产欧美精品日韩精品| 韩国中文免费在线视频| 在线亚洲欧美视频| 免费男女羞羞的视频网站在线观看| 韩国av一区二区| 久久亚洲精品网站| 1区2区3区在线视频| 中文子幕无线码一区tr| 国产精品入口尤物| 女人天堂av手机在线| www.久久东京| 4k岛国日韩精品**专区| 老司机精品视频在线播放| 色综合影院在线| 国产免费永久在线观看| 亚洲精品欧美二区三区中文字幕| 高清成人av| 欧洲精品在线观看| 91美女主播在线视频| 国产女精品视频网站免费| 色呦呦在线免费观看| 欧美成人激情图片网| 91成人影院| 国产91在线视频观看| 在线观看一区二区精品视频| 欧美福利在线播放| 成人免费网视频| 国产成人在线电影| 情侣黄网站免费看| 一区二区在线看| 蜜桃视频在线观看网站| 日韩成人在线视频观看| 粉嫩av一区二区| 四虎一区二区| 亚洲男人天堂九九视频| 韩国成人精品a∨在线观看| 国产精品免费观看| 日本成人黄色免费看| 亚洲人成伊人成综合网久久久| 天堂久久久久va久久久久| 瑟瑟视频在线| 日本不卡在线播放| 这里精品视频免费| 日韩美女在线视频| 久久婷婷一区| 国产在线传媒| 亚洲人成网站999久久久综合| 小嫩嫩12欧美| 亚洲国产精品一区在线观看不卡 | 欧美日韩精品综合在线| 欧美国产欧美综合| 欧美日韩尤物久久| 国产成人av网址| 91精品在线一区二区| 极品中文字幕一区| 91蜜桃在线视频| 久久人人爽人人爽人人av| 久久久av亚洲男天堂| 亚洲欧洲综合另类| 久久蜜桃精品| 香蕉久久一区| 韩国福利在线| 真人做人试看60分钟免费| 91精品成人久久| 日韩一区二区精品在线观看| 国产精品1区2区3区| 色老板在线视频一区二区| 国产视频精品久久| 国产精品手机视频| 91老师国产黑色丝袜在线| 欧美**字幕| 性欧美18xxxhd| 最新在线观看av| 欧美 亚洲 视频| caoporen国产精品| 欧美日本视频在线| 国产福利一区二区三区视频| 欧美日韩123| 成人免费在线观看视频| 里番在线观看网站| 亚洲色图16p| www.com黄色片| 亚洲精品久久久久久一区二区| 国产精品普通话| 国产一区二区三区四区福利| 欧美日韩一区二区三区四区| 一级日本不卡的影视| 18欧美亚洲精品| 欧美激情一区二区三区全黄| 亚洲欧美日韩视频二区| 精品国产乱码久久久| 成午夜精品一区二区三区软件| 天堂网在线免费观看| koreanbj精品视频一区| 中文字幕日韩欧美在线| 2021久久国产精品不只是精品| 国产三级伦理在线| 国产日本在线视频| 国产视频第一区| av在线播放网| 欧美人与禽猛交乱配| 在线手机中文字幕| 91精品国产一区二区在线观看| 国产日韩欧美中文在线| 激情小说亚洲色图| 午夜日韩av| 精品在线免费观看| 国产精品视频yy9299一区| 亚欧色一区w666天堂| 91精品国产综合久久福利软件 | 偷偷要 色偷偷| 粉嫩一区二区三区国产精品| 污网站在线免费看| 日本免费一区二区视频| 欧美成人a交片免费看| 久久久亚洲欧洲日产| 中文在线播放一区二区| 国产麻豆9l精品三级站| 欧美高清在线视频| 欧美少妇一区二区| 久精品免费视频| 久久综合给合久久狠狠色| av视屏在线播放| 女囚岛在线观看| 日韩免费成人| 亚洲综合社区| 亚洲国产精品嫩草影院| 精品呦交小u女在线| 精品一区二区三区国产| 国产精品久久久久久久av电影| 中文字幕免费精品一区| 久久中文字幕一区| 欧美日韩高清区| 国产综合久久久久久| 日韩免费av一区二区| 国产精品免费福利| 99热这里只有精品免费| 在线免费黄色毛片| 巨大黑人极品videos精品| 欧美ab在线视频| 亚洲精品成人a在线观看| 亚洲成人av资源网| 亚洲精品videosex极品| 一区二区三区欧美日| 亚洲一区二区三区四区的| 日韩中文欧美在线| 欧美国产日韩一二三区| 舔着乳尖日韩一区| 日韩亚洲欧美一区| 国产精品久久久久91| 91久久国产综合久久蜜月精品| 椎名由奈jux491在线播放| 中文字幕欧美日韩一区二区| www.玖玖玖| 成全电影大全在线观看| 日韩在线观看一区二区三区| 全球成人免费直播| 日韩精品成人一区二区三区| 自拍偷拍国产亚洲| 国产亚洲人成a一在线v站| 97干在线视频| 亚洲涩涩在线| 777午夜精品电影免费看| 蜜芽在线免费观看| 美女高潮视频在线看| 99久久夜色精品国产亚洲96| 外国成人免费视频| 日韩欧美亚洲一区二区| 国产欧美亚洲视频| 国产区一区二区| 最近中文字幕在线| 自拍偷拍亚洲视频| 国模一区二区三区| 国产精品久久久久aaaa|