算法导论 之 红黑树 - 添加[C语言]

 

 

 

 

1 引言

    在之前的博文中,本人对平衡二叉树的处理做了较详尽的分析,有兴趣的朋友可以参阅博文《算法导论 之 平衡二叉树 - 创建 插入 搜索 销毁》和《算法导论 之 平衡二叉树 - 删除》。平衡二叉树AVL是严格的平衡树,在增删结点时,其旋转操作的次数较多;而红黑树RBT则通过非严格的平衡来换取增删结点时旋转次数的降低。在应用中,如果搜索次数大于增删次数,则选择平衡二叉树更好一些;而如果搜索与增删次数接近时,红黑树则是更好的选择。在有些资料中显示,红黑树的统计性能要优于平衡二叉树。

 

2 性质分析

    红黑树是一种二叉查找树,但在每个节点上增加一个存储位表示结点的颜色[RED或BLACK]。通过对任一结点到叶子结点的路径上各个结点着色方式的限制,确保没有一条路径会是其他路径的2倍,因而是接近平衡的!因此,它能保证在最坏情况下,基本的动态集合操作的时间复杂度为O(log2@N)[log2@N:以2为底数,N为对数][注:理论上平衡二叉树的性能要优于红黑树,但是仍处同一数量级]

图1 红黑树

    红黑树有以下5种性质,所有对红黑树的处理都是围绕这5种性质进行的。但是想通过以下5种性质的简单描述就期望能够深入理解红黑树,这似乎是不太可能的事情。因此,下面将结合图1对其5种性质进行分别的解析。

 ①、每个节点要么是红色的,要么是黑色的;

    解析:任何一个结点都有一种颜色 —— 非红即黑。从图1中可以清楚的看出这一点。

 ②、根结点是黑色的;

    解析:根结点只能为黑色,不可能为红色。如图1中的根结点为13,其为黑色。

 ③、所有叶子结点(NIL)都是黑色的;

    解析:在图1中的所有叶子结点(NIL)的颜色只能为黑色的,不可能为红色。

 ④、如果一个结点是红色,则它的两个儿子都是黑色的;

    解析:如图1中的结点6、8、17、22、27为红色结点,其左右孩子结点只能为黑色。即:树中决不允许存在两个连续的红色结点。[注:但是允许两个连续的黑色结点]

 ⑤、对任何一个结点,从该结点通过其子孙结点到达叶子结点(NIL)的所有路径上包含相同数目的黑结点。

    解析:以根结点为例,其通过子孙结点到达叶子节点(NIL)的路径有如下几种情况:

        路径1:13(b) -> 8(r) -> 1(b) -> 叶子(b)            | 3个黑结点:13、1、叶子

        路径2:13(b) -> 8(r) -> 11(b) -> 叶子(b)           | 3个黑结点:13、11、叶子

        路径3:13(b) -> 8(r) -> 1(b) -> 6(r) -> 叶子(b)    | 3个黑结点:13、1、叶子

        路径4: 13(b) -> 17(r) -> 25(b) -> 22(r) -> 叶子(b) | 3个黑结点:13、25、叶子

        路径5: 13(b) -> 17(r) -> 25(b) -> 27(r) -> 叶子(b) | 3个黑结点:13、25、叶子

        路径6: 13(b) -> 17(r) -> 15(b) -> 叶子(b)          | 3个黑结点:13、15、叶子

        ....

      至此,大家应该能够明白性质⑤的真实含义了。

    为了便于处理红黑树代码的边界条件,我们采用一个哨兵来代表NIL。对于一个红黑树而言,哨兵NIL是一个与树内普通结点有相同域的对象。它的color域为BLACK,而其他域(parent,lchild,rchild和key)的值我们并不关心。

    总之,红黑树是通过以上5种性质的限制约束了该树的平衡性能 —— 即:该树上的最长路径长度不可能大于最短路径长度的2倍,从而确保对树操作的时间复杂度达到O(log2@N)。

 

3 编码实现

3.1 结构定义

①、常值定义:增强代码可读性、方便代码修改

/* 常值定义 */
#define RBT_COLOR_BLACK    'b'     /* 颜色:黑色 */
#define RBT_COLOR_RED      'r'     /* 颜色:红色 */

#define RBT_LCHILD         (0)     /* 类型:左孩子 */
#define RBT_RCHILD         (1)     /* 类型:右孩子 */

#define RBT_MAX_DEPTH      (512)   /* 栈的深度(栈处理红黑树时使用) */

代码1 常值定义

②、节点结构:在二叉查找树的结构基础上,新增color字段

/* 结点结构 */
typedef struct _rbt_node_t {
    int key;                        /* 关键字 */
    int color;                      /* 结点颜色: RBT_COLOR_BLACK(黑) 或 RBT_COLOR_RED(红) */
    struct _rbt_node_t *parent;     /* 父节点 */
    struct _rbt_node_t *lchild;     /* 左孩子节点 */
    struct _rbt_node_t *rchild;     /* 右孩子节点 */
} rbt_node_t;

代码2 结点结构

③、树结构:sentinel字段用于表示叶子结点(NIL)。当树内结点的左(右)孩子为叶子结点时,则将左(右)孩子指针指向sentinel字段。

/* 红黑树结构 */
typedef struct {
    rbt_node_t *root;               /* 根节点 */
    rbt_node_t *sentinel;       
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值