引言  — 红黑树历史

顿时点儿天,“A4腰”一夜间爆红,熊黛林、袁姗姗、张俪、王丽坤等大腕纷纷于微博及晾晒起自己的A4腰,还有很多男神也曝出了靓照。看到不少网友流在口水羡慕嫉妒妒恨,我不由回想起了十几年前的温馨。曾经的自,别说凡是A4腰,就连普通码最要命号的衣都通过无下。曾经的自身,是独肥胖,今天虽跟豪门说说自要好的那段满是汗的早晚。另,熟悉宝叔的对象或会见意识这首文章和往统统不同之作风,呵呵,谁还尚未简单内心的稍故事啊,您说是不是?

  红黑树是数据结构学习中一律鸣卡. 底层库容器中必不可少的终究法.
历经各种实战运用,性能有保障. 同样红黑树不好理解, 就算理解了,
代码也不好写.

1.本人就是独无知的胖

自小自己就老辈人最喜爱的型。没错,就是“大胖男”,我好光荣地获取妻子爷爷奶奶、姥姥姥爷、爸爸妈妈、亲戚朋友、街坊邻居们的慈,一直以来周围的亲们总像魔术师一样变来过多鲜的,然后塞到本人之嘴里。但任何都发生代价,我的代价就是从小便没有丢喽油,婴儿肥就无减下来过,然后打小学一直顶高校。

说自己要好“无知”,绝对实事求是,当年之自家从来未曾发现及“胖”已经渐渐侵蚀了自我之生存,当然为从未想过如果反自己之留存模式,而且固执地当胖是天的,是无法更改之,不用太注意。即使在高中,大家还早就起发出矣小伙子自己的审美,有的胖友已经勇敢地从头了减肥,我还是“无知”地认为那些还纯粹是拉,胖是天生的,几乎是无能为力更改之。

总之,我于懵懵懂懂中带来在同等身膘儿就直达了高校。我是法中文的,当年我们学校是“211”“985”里面排名特别对的综合大学,文科学院基本还当一个校区,真是“乱花渐欲迷人眼”啊,从无见了这么多尴尬的幼女呀。毕业十年的聚首上,班里的哥们儿纷纷确认非常一即没学过习,光流着口水看女儿了。于是,问题来了,眼看着周围的哥们一个个花前月下,陪我玩游戏的越来越少,找我借钱之更是多,但是——没有女爱上我,没有女爱上我,没有女儿爱上我。重要之事体说其三布满。

说实话,眼红心热啊,但人口总是喜欢生活在惯性力,就像当年的自,仍然顽固地活在自己的社会风气里,哪怕周围的小兄弟等早已渐渐开始于本人投来嘲笑的秋波。人,有的时候要一点点源于异性的激,我认同最终深受自家顿觉的莫是什么惊天动地上之理,就是一个机缘巧合的时机,也许是天实在是坏我这样情商低的胖子,我闻了自我班几乎个淑女在默默对我的议论。

好吧,实在不思复述那些话语了,但我感谢那些话,其中还有我一直暗恋的班花……一管辛酸泪啊,哎……

就是到了这么的时刻,我仍以徘徊,觉得减肥这个工作的科学性有待验证,特别是家长辈只要听到我如果减肥,一准儿反对,主要从健康及人生观两独角度劝我,健康角度就是说人最好关键呀,节食最伤害人啊,运动吧要是循序渐进啊什么的,人生观角度主要是说走自己的路程,让别人说错过吧,人如效仿在成熟地接收自己等等。这里,非常感谢我大学之同一号姓程的体育老师,当年行程先生曾经五十几近岁了,但看正在就比如四十无顶之规范,每天都浑身充满力量,对咱们这些体育困难户也杀关照。

当我以大二暑假前之一个中午无意和程老师说从自己之迷惑的时光,程先生充满深意地圈了自家同一目,然后云淡风轻地游说:

面容是家长给您的福泽,身材是你针对好的神态,当运动的确融入你的生,你晤面当里感受及均等栽对协调身体掌控的喜气洋洋,你见面发觉一个更是阳光与满力量的友好,那是均等切片特别美好的圈子。

说这话的时刻,程先生刚于网球场回来,网球衫湿透,印有石凿斧刻般的胸腹肌,中午的日光让程先生短发上之津闪闪发光,我现记忆犹新,仿佛就以昨天。

……

自从大三开始,我开跑和健身了,中间的汗水、泪水还是血水这里虽无多说了,总的好四毕业的时光,我减掉了五十斤,体重回归正常范围,扔掉了装有之前的衣,敢穿越塑身衣在球场上踢球炫胸腹肌,也能够引来广大女生闪闪发亮的眼力,换了一个人。

自己渐渐掌握,任何的好身材背后都见面发成百上千我们看不到的汗液,我之阅历告知我,没有同栽好身材是不需全力以赴保护的,而且接近就世上的不少从业还是是道理。

尽管写了, 工程库也难构建.
关于红黑树基础讲解推荐看下博主的红黑树博文系列,感觉不错.

2.蜕变后,你才会看清你协调

自己当胖胖的那些年实际产生为数不少疾患,因为当局者迷,所以自己直接从未发现。后来,当都于“有型”的自我回头看自己的当儿,才逐渐明白程老师的远大。

此前的自身确实是非常疲倦。只有开始活动之后,你才会窥见你生出多懒,早晨起床跑步永远是千篇一律会生决战,那些家伙动作的组数永远都没法儿达到。但自忽然发现虽然好运动的经过是屡败屡战,自己对团结挺不令人满意,但上学和在中之本身倒是换得巧了,变得紧了,变得努力多矣。

原先的自身真正是生宅。别人我莫懂得,反正自己当好的胖和宅也来非常酷关系,因为宅可以增加多而疲惫的空子,让您可以很畅快地窝在宿舍里,于是体重为会格外舒服地上升。但运动后,我发觉下楼然后蒸发至操场及,或者下办事儿和读书并无是一致起天特别之难题,也日趋觉得宅在宿舍里其实没什么意思。

早先的本身实在是不行死。别看那时的我胖,但同时提心吊胆热,又害怕凉,还容易感个顶什么的,而且还只有骄气。那种虚弱感身在其中不见面掌握,只有真正走来了团结才能够回望到。当你将周人倒了四起,那种活力的回归感,那种对人的慢慢掌控感,会于您欢天喜地。而且,你会意识你再度像一个汉子了,更加抗冻抗热,一般的小病小伤啊什么的,你都见面老MAN地划过去。

先的自己实在是甚怂。因为自己疲惫、宅、弱,所以遇到事情的时光会习惯性地煽动一些,不敢大胆地失去品尝,害怕改变,害怕吃苦,害怕矛盾,自己为特别拖延,做政工特犹豫,自己也憋。运动之后,特别是望好突破了许多和好原先未敢想象的疑惑的时刻,你晤面深感自己便是斯巴达的斗士。比如从小胖的男生,胸前会发赘肉,这吃人分外窘迫,以前自己还上网查过,说啊的且来,很多还立在“科学”和“专业”的角度为胖子们泼冷水,说就是脂肪堆积时间了长造成雌激素分泌,导致胸腺的强盛。狗屁!狗屁!狗屁!我为这个判断忽悠了未是平年两年,上医院整形的心中都来矣。其实,胖友们而去丢胸前的“尴尬”,就是放下卧撑、飞鸟、卧推,就是咬牙流汗和调谐并了!你晤面发现网上“专家”的放屁,你会意识你的汗水不会见白流,自己胸前那片堆放“尴尬”不知不觉被于逐年变硬,形状在日益收紧,直到发生一致上若突然扭头看了平肉眼穿衣镜,发现了和睦挺拔的胸肌,那种怀念哭的痛感自我现还记得。

科学,我转了自己,胸是挺的,腰是直的,臀是翘的,整个人口的态度变得挺拔,不敢说玉树临风,但起码是满载了力量,那种阳刚之自信给人口格外振奋,做啊业务还变得愈加无畏,更加会努力,甚至连平素话唠的病症都看好了,因为,运动让你知了走路进一步要。

  红黑树(一)之
原理同算法详细介绍 

3.掌控身材是掌控人生的率先步

干活十差不多年了,从正出道的青涩骚年,到现在逐渐稳定的单位中层,从没房没车没有老婆的单身狗,到今车、房、老婆、儿子齐全的奔四大叔,自己虽非到底成,但也于日益成长,自己虽然注定平凡,但可了得充实幸福。

这些年,虽然工作吧忙碌也累,虽然事情呢大都为夹杂,但移动一直随同着本人。客观的游说,工作后确实会当一些挪的困顿,特别是发出了儿女以后,时间换得专程紧张,这些还是新的挑战。为了能不误事,我一般每天早晨5点半从床跑步,跑步前将早上之粥先煲上,一个时慢跑回去会做片力量训练,比如现在十二分火之“囚徒健身”、“腹肌撕裂者”什么的,然后准备早餐,时间都还吓,然后上班,一天发生精神,感觉特别旺盛。

毕业十年聚会的下,当年之“嘻哈猴”、“小虾米”、“狗头”等兄弟都早就“大腹便便”,当年次上的几乎枚金花也还开堵小腹的赘肉。我修身款的商务休闲为同学惊艳,他们说马上是次独没有悟出,第一独凡是读的上没悟出自己能脱胎换骨,第二只是绝非悟出十年晚自己还能够保持稳健,这第二个是绝从未悟出,聚会后我让封“天山童姥”,巨汗……另外,还有家里的老婆大人,有时自己飞步回去浑身是汗,换下走步服去洗澡,老婆大人会忽然窜出来,一改职场女强人的风骨,扮作花痴状满眼星星地冲在自己“欧巴,欧巴”,让我备感婚姻设惦记维持新鲜,除了依靠彼此经营,更使倚重自己之连努力,不断成长。

掌控人生是独宏观的命题,说实话,我未敢妄言,但尽管自己好之更来说,我以为掌控身材是首先步,身材的掌控其实是一个系统工程,里面富含着很多因素,每个因素还是一律种植自我挑战。比如自己眼前提到的朝5点半于床跑步,其实私下的系统是你必须使于前天晚间保证10点钟睡,别小看这个早睡早起,直到现在我哉未敢说自真完全能够完成。再按要掌控身材,除了活动,还要是设置饮食,呵呵,这个不用多说了吧,你当挡住一块儿红烧肉或者巧克力的死活运用水平,有时候不比较坐怀不乱小哦。可以测算掌控身材的过程中,我们就要面对的不要是短期的作战,而是相同集市长期之战役。

森兄弟姐妹们或会说,这么在多麻烦啊,人生苦短,不值得啊。没错,大家怎么看待自己,选择什么的生,都是同种植天然的权利,这种权利神圣而不得犯,我啊仅是将协调的有涉将出来和豪门享受,至于你挑选啊,只要自己觉得多幸福就哼什么。

唯独,我思念我当还理解许多胖的苦涩:朋友,你是不是也是一个诸如自家一样的肥?你是不是为发出了心扉之垂死挣扎以及惨痛?你是不是为因为好的个头而舍了暗恋的孩童?你是不是过多不成幻想过好减肥成后底楷模?你是不是当静静的的时候得到在半承保薯片无声叹息?

最少,曾经有个肥胖,这样悄悄生活了诸多年,今天也公勾勒下方面吧,愿你敢地跨过挑战自己之率先步,你一定好的,加油!

对此红黑树小背景简介摘抄如下:

  红黑树(英语:Red–black
tree)是一种由平衡二叉查找树,是在微机对被因故到之等同栽数据结构,典型的用处是贯彻提到数组。它是在1972年由鲁道夫·贝尔表的,他称之为”对如二叉B树”,它现代之名是于Leo
J. Guibas和Robert
Sedgewick为1978年勾勒的同篇论文被拿走的。它是复杂的,但她的操作有美好的最为老情况运行时,并且在实践中是便捷的:它可于O(log
n)时间外开查找,插入和去,这里的n凡培训中元素的数码。

对于红黑树更加详细的史参考下资料.

  红黑树
https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91

本文重点介绍工程开发中, 红黑树工程基库的封装.直接用现成的卓绝爽.

 

前言  — 红黑树工程库源码

   一言不合就达成源码! 

rbtree.h

#ifndef _H_RBTREE
#define _H_RBTREE

struct rbnode {
    unsigned long    parent_color;
    struct rbnode * right;
    struct rbnode * left;
};

typedef void * (* new_f)(void *);
typedef int (* cmp_f)(const void *, const void *);
typedef void (* die_f)(void *);

typedef struct {
    struct rbnode * root;
    new_f new;
    cmp_f cmp;
    die_f die;
} * rbtree_t;

/*
 * 每个想使用红黑树的结构, 需要在头部插入下面宏. 
 * 例如 :
    struct person {
        _HEAD_RBTREE;
        ... // 自定义信息
    };
 */
#define _HEAD_RBTREE    struct rbnode __node

/*
 * 创建一颗红黑树头结点 
 * new        : 注册创建结点的函数
 * cmp        : 注册比较的函数
 * die        : 注册程序销毁函数
 *            : 返回创建好的红黑树结点
 */
extern rbtree_t rb_new(new_f new, cmp_f cmp, die_f die);

/*
 * 插入一个结点, 会插入 new(pack)
 * tree        : 红黑树头结点
 * pack        : 待插入的结点当cmp(x, pack) 右结点
 */
extern void rb_insert(rbtree_t tree, void * pack);

/*
 * 删除能和pack匹配的结点
 * tree        : 红黑树结点
 * pack        : 当cmp(x, pack) 右结点
 */
extern void rb_remove(rbtree_t tree, void * pack);

/*
 * 得到红黑树中匹配的结点
 * tree        : 匹配的结点信息
 * pack        : 当前待匹配结点, cmp(x, pack)当右结点处理
 */
extern void * rb_get(rbtree_t tree, void * pack);

/*
 * 销毁这颗二叉树
 * tree        : 当前红黑树结点
 */
extern void rb_die(rbtree_t tree);

#endif /* _H_RBTREE */

rbtree.c

图片 1图片 2

#include "rbtree.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * 操作辅助宏, 得到红黑树中具体父结点, 颜色. 包括详细设置信息
 * r    : 头结点
 * p    : 父结点新值
 * c    : 当前颜色
 */
#define rb_parent(r)        ((struct rbnode *)((r)->parent_color & ~3))
#define rb_color(r)            ((r)->parent_color & 1)
#define rb_is_red(r)        (!rb_color(r))
#define rb_is_black(r)        rb_color(r)
#define rb_set_black(r)        (r)->parent_color |= 1
#define rb_set_red(r)        (r)->parent_color &= ~1

static inline void rb_set_parent(struct rbnode * r, struct rbnode * p) {
     r->parent_color = (r->parent_color & 3) | (unsigned long)p;
}

static inline void rb_set_color(struct rbnode * r, int color) {
     r->parent_color = (r->parent_color & ~1) | (1 & color);
}

static inline int _rb_cmp(const void * ln, const void * rn) {
    return (const char *)ln - (const char *)rn;
}

 /*
  * 创建一颗红黑树头结点
  * new        : 注册创建结点的函数
  * cmp        : 注册比较的函数
  * die        : 注册程序销毁函数
  *            : 返回创建好的红黑树结点
  */
rbtree_t 
rb_new(new_f new, cmp_f cmp, die_f die) {
    rbtree_t tree = malloc(sizeof(*tree));
    if(NULL == tree) {
        fprintf(stderr, "rb_new malloc is error!");
        return NULL;    
    }

    tree->root = NULL;
    tree->new = new;
    tree->cmp = cmp ? cmp : _rb_cmp;
    tree->die = die;

    return tree;
}

static inline struct rbnode * _rb_new(rbtree_t tree, void * pack) {
    struct rbnode * node = tree->new ? tree->new(pack) : pack;
    memset(node, 0, sizeof(struct rbnode));
    return node;
}

/* 
 * 对红黑树的节点(x)进行左旋转
 *
 * 左旋示意图(对节点x进行左旋):
 *      px                              px
 *     /                               /
 *    x                               y                
 *   /  \      --(左旋)-->           / \                #
 *  lx   y                          x  ry     
 *     /   \                       /  \
 *    ly   ry                     lx  ly  
 *
 */
static void _rbtree_left_rotate(rbtree_t tree, struct rbnode * x) {
    // 设置x的右孩子为y
    struct rbnode * y = x->right;
    struct rbnode * xparent = rb_parent(x);

    // 将 “y的左孩子” 设为 “x的右孩子”;
    x->right = y->left;
    // 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲”
    if (y->left != NULL)
        rb_set_parent(y->left, x);

    // 将 “x的父亲” 设为 “y的父亲”
    rb_set_parent(y, xparent);

    if (xparent == NULL)
        tree->root = y;            // 如果 “x的父亲” 是空节点,则将y设为根节点
    else {
        if (xparent->left == x)
            xparent->left = y;     // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”
        else
            xparent->right = y;    // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”
    }

    // 将 “x” 设为 “y的左孩子”
    y->left = x;
    // 将 “x的父节点” 设为 “y”
    rb_set_parent(x, y);
}

/* 
 * 对红黑树的节点(y)进行右旋转
 *
 * 右旋示意图(对节点y进行左旋):
 *            py                               py
 *           /                                /
 *          y                                x                  
 *         /  \      --(右旋)-->            /  \                     #
 *        x   ry                           lx   y  
 *       / \                                   / \                   #
 *      lx  rx                                rx  ry
 * 
 */
static void _rbtree_right_rotate(rbtree_t tree, struct rbnode * y) {
    // 设置x是当前节点的左孩子。
    struct rbnode * x = y->left;
    struct rbnode * yparent = rb_parent(y);

    // 将 “x的右孩子” 设为 “y的左孩子”;
    y->left = x->right;
    // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”
    if (x->right != NULL)
        rb_set_parent(x->right, y);

    // 将 “y的父亲” 设为 “x的父亲”
    rb_set_parent(x, yparent);
    if (yparent == NULL) 
        tree->root = x;                // 如果 “y的父亲” 是空节点,则将x设为根节点
    else {
        if (y == yparent->right)
            yparent->right = x;        // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”
        else
            yparent->left = x;        // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”
    }

    // 将 “y” 设为 “x的右孩子”
    x->right = y;
    // 将 “y的父节点” 设为 “x”
    rb_set_parent(y, x);
}

/*
 * 红黑树插入修正函数
 *
 * 在向红黑树中插入节点之后(失去平衡),再调用该函数;
 * 目的是将它重新塑造成一颗红黑树。
 *
 * 参数说明:
 *     tree 红黑树的根
 *     node 插入的结点        // 对应《算法导论》中的z
 */
static void _rbtree_insert_fixup(rbtree_t tree, struct rbnode * node) {
    struct rbnode * parent, * gparent, * uncle;

    // 若“父节点存在,并且父节点的颜色是红色”
    while ((parent = rb_parent(node)) && rb_is_red(parent)) {
        gparent = rb_parent(parent);

        //若“父节点”是“祖父节点的左孩子”
        if (parent == gparent->left) {
            // Case 1条件:叔叔节点是红色
            uncle = gparent->right;
            if (uncle && rb_is_red(uncle)) {
                rb_set_black(uncle);
                rb_set_black(parent);
                rb_set_red(gparent);
                node = gparent;
                continue;
            }

            // Case 2条件:叔叔是黑色,且当前节点是右孩子
            if (parent->right == node) {
                _rbtree_left_rotate(tree, parent);
                uncle = parent;
                parent = node;
                node = uncle;
            }

            // Case 3条件:叔叔是黑色,且当前节点是左孩子。
            rb_set_black(parent);
            rb_set_red(gparent);
            _rbtree_right_rotate(tree, gparent);
        } 
        else { //若“z的父节点”是“z的祖父节点的右孩子”
            // Case 1条件:叔叔节点是红色
            uncle = gparent->left;
            if (uncle && rb_is_red(uncle)) {
                rb_set_black(uncle);
                rb_set_black(parent);
                rb_set_red(gparent);
                node = gparent;
                continue;
            }

            // Case 2条件:叔叔是黑色,且当前节点是左孩子
            if (parent->left == node) {
                _rbtree_right_rotate(tree, parent);
                uncle = parent;
                parent = node;
                node = uncle;
            }

            // Case 3条件:叔叔是黑色,且当前节点是右孩子。
            rb_set_black(parent);
            rb_set_red(gparent);
            _rbtree_left_rotate(tree, gparent);
        }
    }

    // 将根节点设为黑色
    rb_set_black(tree->root);
}

/*
 * 插入一个结点, 会插入 new(pack)
 * tree        : 红黑树头结点
 * pack        : 待插入的结点当cmp(x, pack) 右结点
 */
void 
rb_insert(rbtree_t tree, void * pack) {
    cmp_f cmp;
    struct rbnode * node, * x, * y;
    if((!tree) || (!pack) || !(node = _rb_new(tree, pack))) {
        fprintf(stderr, "rb_insert param is empty! tree = %p, pack = %p.\n", tree, pack);
        return;    
    }

    cmp = tree->cmp;
    // 开始走插入工作
    y = NULL;
    x = tree->root;

    // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。从小到大
    while (x != NULL) {
        y = x;
        if (cmp(x, node) > 0)
            x = x->left;
        else
            x = x->right;
    }
    rb_set_parent(node, y);

    if (y != NULL) {
        if (cmp(y, node) > 0)
            y->left = node;             // 情况2:若“node所包含的值” < “y所包含的值”,则将node设为“y的左孩子”
        else
            y->right = node;            // 情况3:(“node所包含的值” >= “y所包含的值”)将node设为“y的右孩子” 
    }
    else
        tree->root = node;              // 情况1:若y是空节点,则将node设为根

    // 2. 设置节点的颜色为红色
    rb_set_red(node);

    // 3. 将它重新修正为一颗二叉查找树
    _rbtree_insert_fixup(tree, node);
}

/*
 * 红黑树删除修正函数
 *
 * 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数;
 * 目的是将它重新塑造成一颗红黑树。
 *
 * 参数说明:
 *     tree 红黑树的根
 *     node 待修正的节点
 */
static void _rbtree_delete_fixup(rbtree_t tree, struct rbnode * node, struct rbnode * parent) {
    struct rbnode * other;

    while ((!node || rb_is_black(node)) && node != tree->root) {
        if (parent->left == node) {
            other = parent->right;
            if (rb_is_red(other)) {
                // Case 1: x的兄弟w是红色的  
                rb_set_black(other);
                rb_set_red(parent);
                _rbtree_left_rotate(tree, parent);
                other = parent->right;
            }
            if ((!other->left || rb_is_black(other->left)) &&
                (!other->right || rb_is_black(other->right))) {
                // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的  
                rb_set_red(other);
                node = parent;
                parent = rb_parent(node);
            }
            else {
                if (!other->right || rb_is_black(other->right)) {
                    // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。  
                    rb_set_black(other->left);
                    rb_set_red(other);
                    _rbtree_right_rotate(tree, other);
                    other = parent->right;
                }
                // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
                rb_set_color(other, rb_color(parent));
                rb_set_black(parent);
                rb_set_black(other->right);
                _rbtree_left_rotate(tree, parent);
                node = tree->root;
                break;
            }
        }
        else {
            other = parent->left;
            if (rb_is_red(other)) {
                // Case 1: x的兄弟w是红色的  
                rb_set_black(other);
                rb_set_red(parent);
                _rbtree_right_rotate(tree, parent);
                other = parent->left;
            }
            if ((!other->left || rb_is_black(other->left)) &&
                (!other->right || rb_is_black(other->right))) {
                // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的  
                rb_set_red(other);
                node = parent;
                parent = rb_parent(node);
            }
            else {
                if (!other->left || rb_is_black(other->left)) {
                    // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。  
                    rb_set_black(other->right);
                    rb_set_red(other);
                    _rbtree_left_rotate(tree, other);
                    other = parent->left;
                }
                // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
                rb_set_color(other, rb_color(parent));
                rb_set_black(parent);
                rb_set_black(other->left);
                _rbtree_right_rotate(tree, parent);
                node = tree->root;
                break;
            }
        }
    }
    if (node)
        rb_set_black(node);
}

/*
 * 删除rb_get得到的结点
 * root        : 红黑树结点
 * pack        : 当cmp(x, pack) 右结点
 */
void 
rb_remove(rbtree_t tree, void * pack) {
    struct rbnode * child, * parent, * node = NULL;
    int color;

    if ((!tree) || !(node = (struct rbnode *)pack)) {
        fprintf(stderr, "rb_remove check is error, tree = %p, node = %p.", tree, node);
        return;
    }

    // 被删除节点的"左右孩子都不为空"的情况。
    if (NULL != node->left && node->right != NULL) {
        // 被删节点的后继节点。(称为"取代节点")
        // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
        struct rbnode * replace = node;

        // 获取后继节点
        replace = replace->right;
        while (replace->left != NULL)
            replace = replace->left;

        // "node节点"不是根节点(只有根节点不存在父节点)
        if ((parent = rb_parent(node))) {
            if (parent->left == node)
                parent->left = replace;
            else
                parent->right = replace;
        } 
        else 
            // "node节点"是根节点,更新根节点。
            tree->root = replace;

        // child是"取代节点"的右孩子,也是需要"调整的节点"。
        // "取代节点"肯定不存在左孩子!因为它是一个后继节点。
        child = replace->right;
        parent = rb_parent(replace);
        // 保存"取代节点"的颜色
        color = rb_color(replace);

        // "被删除节点"是"它的后继节点的父节点"
        if (parent == node)
            parent = replace; 
        else {
            // child不为空
            if (child)
                rb_set_parent(child, parent);
            parent->left = child;

            replace->right = node->right;
            rb_set_parent(node->right, replace);
        }

        rb_set_parent(replace, rb_parent(node));
        rb_set_color(replace, rb_color(node));
        replace->left = node->left;
        rb_set_parent(node->left, replace);

        if (color) // 黑色结点重新调整关系
            _rbtree_delete_fixup(tree, child, parent);
        // 结点销毁操作
        if(tree->die)
            tree->die(node);
        return ;
    }

    if (node->left !=NULL)
        child = node->left;
    else 
        child = node->right;

    parent = rb_parent(node);
    // 保存"取代节点"的颜色
    color = rb_color(node);

    if (child)
        rb_set_parent(child, parent);

    // "node节点"不是根节点
    if (parent) {
        if (parent->left == node)
            parent->left = child;
        else
            parent->right = child;
    }
    else
        tree->root = child;

    if (!color)
        _rbtree_delete_fixup(tree, child, parent);
    if(tree->die)
        tree->die(node);
}

/*
 * 得到红黑树中匹配的结点
 * root        : 匹配的结点信息
 * pack        : 当前待匹配结点, cmp(x, pack)当右结点处理
 */
void * 
rb_get(rbtree_t tree, void * pack) {
    cmp_f cmp;
    struct rbnode * node;
    if((!tree) || !pack) {
        fprintf(stderr, "rb_get param is empty! tree = %p, pack = %p.\n", tree, pack);
        return NULL;    
    }

    cmp = tree->cmp;
    node = tree->root;
    while(node) {
        int ct = cmp(node, pack);
        if(ct == 0)
            return node;
        node = ct > 0 ? node->left : node->right;
    }

    return NULL;
}

// 后序遍历删除操作
static void _rb_die(struct rbnode * root, die_f die) {
    if(NULL == root)
        return;
    _rb_die(root->left, die);
    _rb_die(root->right, die);
    die(root);
}

/*
 * 销毁这颗二叉树
 * root        : 当前红黑树结点
 */
void
rb_die(rbtree_t tree) {
    if(!tree || !tree->root || !tree->die)
        return;

    // 后续递归删除
    _rb_die(tree->root, tree->die);

    // 销毁树本身内存
    tree->root = NULL;
    free(tree);
}

View Code

上面代码主要基于linux内核中瑞黑树扒下构建的工库.
有些细节我们简要解释一下结构.  例如

/*
 * 每个想使用红黑树的结构, 需要在头部插入下面宏. 
 * 例如 :
    struct person {
        _HEAD_RBTREE;
        ... // 自定义信息
    };
 */
#define _HEAD_RBTREE    struct rbnode __node

平等于’继承’用法, 放在没一个盼就此在红黑树结构的峰部.
这些都是起linux内核结构中学到的技巧. libuv框架中吗常常因此这种技巧.
也是C开发被通用潜规则! 还有一个技能, 如下

struct rbnode {
    unsigned long    parent_color;
    struct rbnode * right;
    struct rbnode * left;
};

#define rb_parent(r)        ((struct rbnode *)((r)->parent_color & ~3))
#define rb_color(r)        ((r)->parent_color & 1)

否是于羁押内核源码中学至的艺, 将指针的后2各类地方, 用于保存结点颜色.
为什么可行吗,

因 struct rbnode 结构体内存是以 sizeof (unsigned long) 大小对齐.
那么该组织地址也是盖 n*sizeof(unsigned long) 递增.

后少号都是0空出来的. 用于保存红黑树结点的颜色信息(RED | BLACK).
不得不钦佩linux内核代码的精巧.

后还有一个友好补的技能

typedef void * (* new_f)(void *);
typedef int (* cmp_f)(const void *, const void *);
typedef void (* die_f)(void *);

typedef struct {
    struct rbnode * root;
    new_f new;
    cmp_f cmp;
    die_f die;
} * rbtree_t;

落实登记, 创建, 比较, 销毁行为函数, 方便使用. 采用匿名结构,
也是一个C中付出一个小技巧, 这个结构只能是堆上创建. 对外可见,
但是匪可构建.

末尾会根据这红黑树基础库, 构建一个简繁对照字典. 最后重复一下,
红黑树是软件开发层最后之堡垒. 数据结构算法为就算顶当下了.

 图片 3

 

正巧文  — 简单解析规划和测试

   C的统筹, 主要关押结构. 同样C的难处也是结构.
后面我们做一个简易的简繁转换的字典, 通过C.

用之资源呈现者文件 
http://files.cnblogs.com/files/life2refuel/C%E9%AB%98%E7%BA%A7%E5%B7%A5%E7%A8%8B%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%BA%A2%E9%BB%91%E6%A0%91%E5%9F%BA%E5%BA%93.zip

简繁变换的词典,window上截图如下

图片 4

使的是ascii编码, 这里一个汉字2配节表示. 上传到linux上后,
采用utf-8编码, 一个中文3个字节. 需要小心!

词典主程序 main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rbtree.h"

#define _STR_PATH    "常用汉字简繁对照表.txt"

#define _INT_DICT    (4)

struct dict {
    _HEAD_RBTREE;

    char key[_INT_DICT];
    char value[_INT_DICT];
};

// 需要注册的内容
static void * _dict_new(void * arg) {
    struct dict * node = malloc(sizeof(struct dict));
    if (NULL == node) {
        fprintf(stderr, "_dict_new malloc is error!\n");
        return NULL;
    }

    *node = *(struct dict *)arg;
    return node;
}

static inline int _dict_cmp(const void * ln , const void * rn) {
    return strcmp(((const struct dict *)ln)->key, ((const struct dict *)rn)->key);
}

static inline void _dict_die(void * arg) {
    free(arg);
}

// 创建内容
void dict_create(rbtree_t tree);
// 得到内容
const char * dict_get(rbtree_t tree, const char * key);

/*
 * 这里测试字典数据, 通过红黑树库
 */
int main(int argc, char * argv[]) {
    // 创建字典树, 再读取内容
    rbtree_t tree = rb_new(_dict_new, _dict_cmp, _dict_die);
    if (NULL == tree) {
        fprintf(stderr, "main rb_new rb is error!\n");
        return -1;
    }

    // 为tree填充字典数据
    dict_create(tree);

    // 我们输出一下 '你好'
    printf("你好吗 -> %s%s%s\n", 
        dict_get(tree, "你"), 
        dict_get(tree, "好"),
        dict_get(tree, "吗")
    );

    // 字典书删除
    rb_die(tree);

    getchar();
    return 0;
}

// 创建内容
void 
dict_create(rbtree_t tree) {
    char c;
    struct dict kv;
    // 打开文件内容
    FILE * txt = fopen(_STR_PATH, "rb");
    if (NULL == txt) {
        fprintf(stderr, "main fopen " _STR_PATH " rb is error!\n");
        return;
    }

    while ((c = fgetc(txt))!=EOF) {
        memset(&kv, 0, sizeof kv);
        // 读取这一行key, 并设值
        kv.key[0] = c;
        kv.key[1] = fgetc(txt);

        // 去掉\\t
        c = fgetc(txt);
        if(c < 0) {
            kv.key[2] = c;
            fgetc(txt);
        }

        // 再设置value
        kv.value[0] = fgetc(txt);
        kv.value[1] = fgetc(txt);

        c = fgetc(txt);
        if (c != '\r') {// 这些SB的代码, 都是解决不同系统版本的编码冲突的
            kv.value[2] = c;
            fgetc(txt);
        }

        // 去掉\n
        fgetc(txt);

        // 插入数据
        rb_insert(tree, &kv);
    }

    // 合法读取内容部分
    fclose(txt);
}

// 得到内容
const char * 
dict_get(rbtree_t tree, const char * key) {
    struct dict kv;
    strncpy(kv.key, key, sizeof(kv.key) / sizeof(char));
    struct dict * pkv = rb_get(tree, &kv);
    return pkv ? pkv->value : NULL;
}

先押 window上测试结果

图片 5

点关于  dict_create
关于配置文件分析, 采用最老的编码字符数解析的.

linux上 测试过程如下

图片 6

 图片 7

linux上测试结果充分正常. 到这里, 红黑树基库demo演示了毕. 也许你看好复杂,
但是曾经好粗略了. 因为C程序一个要求就是是,

若需要理解实现. 才能够运用流畅. 一切都是钻木取火, 自生自灭.

闲聊一点, C要是发那种万能数据结构 array 或者 table 那生产率预估会提升10倍.
写代码就跟玩似的. 

今完工等价于C基础数据结构已经全线通工了. C的代码写的越来越多,
越发看好就好!

 

继记  — 一些客气话

  错误是免不了的, 欢迎指正交流增进. 

     回家  
http://music.163.com/\#/song?id=157336

图片 8