C高级 框架开发被吉黑树结构

by admin on 2018年12月15日

看:只吗取悦自己

引言  — 红黑树历史

读,仿佛一向是一律起庄重的政工。大家直接是以局部目标性而读书,取悦他人要读。其实,怎么样在生活中取悦自己,才重新紧要。

  红黑树是数据结构学习着一致志卡. 底层库容器中必不可少的终于法.
历经各个实战运用,性能有保障. 同样红黑树不佳精通, 即使精晓了,
代码也坏写.

小儿,我连无是好读书的子女,我再度易看卡通和影视剧。我弗像有敌人从小便咋一些呀《红楼梦》《三国演义》,上初中就起大仲马,高尔基,雨果(Hugo)。这时候我沉浸于刻钟候底快中,读书对于我是同一种植惩罚。可是每一周我还暴发要要坐下来读之时日。因为自身立了学的几乎客报纸。据说小姑时常看看我拿同堆积报纸摊在地上认真读书,那样子令人忍俊不禁。其实我未是好读报,我只是看那么是为此钱订的,不念好浪费。好吧,尽管是这样一个令人捧腹的理,至少也被了自己的看的一起。

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

当起同样上自己真意识及本人好上读时,即便于在广大书海,感觉无法。其实我真的开头读书吧即便是及时几乎年的日,仿佛长大了成熟了有的,才逐步发现及温馨该起哪的兴趣爱好,该在来什么态度来。

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

一段时间里,我追求阅读的意思。总看进同一本书,看了晚取得特别非常的升级才终于物尽所用。直到后来偶尔听到一词话,“一本书要生一页纸甚至是一律句话,你收益了,这尽管是始终到了立刻仍开之义务。”我不再去纠结一本书带来多少文化,而是去感受与一个丁的魂交换。每一样本书的撰稿人都有其的盘算,都来外一旦揭橥的意。当然,挑一样按部就班好题分外重点。与一个壮烈交流使相比同一个平庸人的交换而好极多。

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

扣押一样本书的时,我衷心连惦念在尽快点看了,知道老结果。就像影片《当哈利被上萨丽》中之哈利(哈利(Harry))说罢:“我请了新书总是先押最后一页,这样的话,假若本身当看罢就本开前然后死去,我虽可以领会就按照开的结果是啊了。”我闻哈利就句话俨然一笑,这家伙很对本身之料。我不怕是这种买来新书必须扣个起来然后慌忙的撸结局的这种人。可当自身精晓结果是什么以后,中间的历程易得索然无味。我就是在那种自相顶牛低度过。就比如你自平诞生,便看到了卿的终身,何时时上什么日期时结婚几不时生子最终怎么死去,那么您的人生就是会了之决不乐趣了咔嚓。假诺无了解结果,那么未来就比如潘Dora盒子里的巧克力糖,永远会变发生您免晓之真容,这名叫惊喜。我晓得自己的短,性子急。我一旦学会试着缓慢下来,学会泡一杯茶,找一个舒适的沙发靠下来,一页页的翻译在题,我弗是为着读了这本开,不是为模仿到什么,而独是以享受它每一样页的悲喜,享受这。

  红黑树(英语:Red–black
tree)是一种由平衡二叉查找树,是在微机是遇之所以到的一样栽数据结构,典型的用途是兑现关联数组。它是在1972年由鲁道夫·贝尔申的,他号称”对如二叉B树”,它现代底名字是以LeoJ. 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

  

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图