libuv tree的實(shí)現(xiàn)

看libuv源碼的時(shí)候能曾,發(fā)現(xiàn)不僅代碼中使用了雙向鏈表,還有一個(gè)伸展樹和紅黑樹的實(shí)現(xiàn)凌简,全部是linux內(nèi)核風(fēng)格的梗夸,數(shù)據(jù)和操作分開,通過宏封裝了指針的操作号醉,實(shí)現(xiàn)的非常精妙反症。

把樹的源碼copy出來,發(fā)現(xiàn)使用起來也非常的簡(jiǎn)單畔派∏Π看看如何使用的吧。

源碼在這里https://github.com/libuv/libuv/blob/v1.x/include/tree.h

由于紅黑樹比伸展樹牛逼线椰,libuv也沒有使用伸展樹胞谈,下面就只聊聊紅黑樹了。

如何使用libuv的紅黑樹

下面的代碼是一個(gè)完整的例子。測(cè)試了插入烦绳,遍歷卿捎,查找,刪除径密,逆向遍歷午阵。


#include "stdafx.h"
#include "tree.h"
#include <malloc.h>

struct node {
    RB_ENTRY(node) entry;
    int i;
};

int
intcmp(struct node *e1, struct node *e2)
{
    return (e1->i < e2->i ? -1 : e1->i > e2->i);
}

RB_HEAD(inttree, node) head = RB_INITIALIZER(&head);
RB_GENERATE(inttree, node, entry, intcmp)

int testdata[] = {
    20, 16, 17, 13, 3, 6, 1, 8, 2, 4, 10, 19, 5, 9, 12, 15, 18,
    7, 11, 14,30,31,32,33
};

int main()
{
    int i;
    struct node *n;

    for (i = 0; i < sizeof(testdata) / sizeof(testdata[0]); i++) {
        if ((n = (struct node *)malloc(sizeof(struct node))) == NULL) {
            printf("malloc return null!!!\n");
            return -1;
        }
        n->i = testdata[i];
        RB_INSERT(inttree, &head, n);
    }

    printf("====================RB_FOREACH=========================\n");
    RB_FOREACH(n, inttree, &head) {
        printf("%d\t", n->i);
    }

    printf("====================RB_NFIND=========================\n");
    {
    struct node theNode;
    theNode.i = 28;
    n = RB_NFIND(inttree, &head, &theNode);
    printf("%d\n", n->i);
    }

    printf("====================RB_FIND=========================\n");
    {
    struct node theNode;
    theNode.i = 20;
    n = RB_FIND(inttree, &head, &theNode);
    printf("%d\n", n->i);
    }

    printf("====================RB_REMOVE=========================\n");
    {
        struct node theNode;
        theNode.i = 20;
        n = RB_FIND(inttree, &head, &theNode);
        printf("find %d first\n", n->i);
        n = RB_REMOVE(inttree, &head, n);
        printf("remove %d success\n", n->i);
    }

    printf("====================RB_FOREACH_REVERSE=========================\n");
    RB_FOREACH_REVERSE(n, inttree, &head) {
        printf("%d\t", n->i);
    }
    printf("\n");

    getchar();
    return (0);
}

程序運(yùn)行結(jié)果

紅黑樹運(yùn)行結(jié)果

可以注意以下幾點(diǎn)

  1. 數(shù)據(jù)結(jié)構(gòu)的定義
    使用RB_ENTRY插入了樹的數(shù)據(jù)結(jié)構(gòu),而自己的數(shù)據(jù)可以任意定義
struct node {
    RB_ENTRY(node) entry;
    int i;
};
  1. 比較函數(shù)
    intcmp實(shí)現(xiàn)了整數(shù)的比較享扔,紅黑樹可以用來排序底桂,可以按優(yōu)先級(jí)取出數(shù)據(jù),比隊(duì)列的查找速度快惧眠。libuv中的timer和signal都使用了rbt籽懦。

  2. RB_GENERATE產(chǎn)生代碼
    由于c語言沒有模板,也不是面向?qū)ο蠓湛膊皇侨躅愋偷哪核常酝ㄟ^宏生成各個(gè)不同名字的紅黑樹代碼是非常巧妙的,實(shí)際上和cpp的模板是一個(gè)效果啊秀存。不過用宏來展開代碼沒法用斷點(diǎn)調(diào)試拖云,我想作者是先寫好測(cè)試用例,或者通過打印來調(diào)試应又,最后沒問題在轉(zhuǎn)成宏的吧。另外乏苦,這種方式導(dǎo)致生成的代碼比較多株扛,和模板的缺點(diǎn)是一樣的。

  3. 宏的技巧
    這里的宏都需要傳入名字汇荐,使用了字符串拼接的技術(shù):比如RB_ENTRY(node) entry;

紅黑樹插入刪除算法

由于算法確實(shí)比較復(fù)雜洞就,以前研究過幾次,現(xiàn)在都記不清楚了掀淘,說明記住算法的步奏確實(shí)是沒有必要的旬蟋,如果想研究算法,確認(rèn)他的效率和正確性革娄,有興趣的可以去看看這篇文章倾贰,我覺得講的還是很清楚的。https://zh.wikipedia.org/wiki/紅黑樹

另外《算法導(dǎo)論》中也對(duì)紅黑樹講的比較多拦惋。

疑問

對(duì)源碼中一個(gè)無用的宏RB_AUGMENT感覺很奇怪匆浙,不知道干什么的。有知道的同學(xué)留言啊厕妖。

#ifndef RB_AUGMENT
#define RB_AUGMENT(x)  do {} while (0)
#endif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末首尼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌软能,老刑警劉巖迎捺,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異查排,居然都是意外死亡凳枝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門雹嗦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來范舀,“玉大人,你說我怎么就攤上這事了罪《Щ罚” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵泊藕,是天一觀的道長(zhǎng)辅辩。 經(jīng)常有香客問我,道長(zhǎng)娃圆,這世上最難降的妖魔是什么玫锋? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮讼呢,結(jié)果婚禮上撩鹿,老公的妹妹穿的比我還像新娘。我一直安慰自己悦屏,他們只是感情好节沦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著础爬,像睡著了一般甫贯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上看蚜,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天叫搁,我揣著相機(jī)與錄音,去河邊找鬼供炎。 笑死渴逻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的音诫。 我是一名探鬼主播裸卫,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼纽竣!你這毒婦竟也來了墓贿?” 一聲冷哼從身側(cè)響起茧泪,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎聋袋,沒想到半個(gè)月后队伟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡幽勒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年嗜侮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啥容。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锈颗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咪惠,到底是詐尸還是另有隱情击吱,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布遥昧,位于F島的核電站覆醇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏炭臭。R本人自食惡果不足惜永脓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞋仍。 院中可真熱鬧常摧,春花似錦、人聲如沸威创。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽那婉。三九已至,卻和暖如春党瓮,著一層夾襖步出監(jiān)牢的瞬間详炬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工寞奸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呛谜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓枪萄,卻偏偏與公主長(zhǎng)得像隐岛,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓷翻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容