红黑树(二)插入

  接下来介绍红黑树的插入操作,介绍插入之前,我们先来了解一下红黑树的性质。

  1、每个节点不是红色就是黑色

  2、跟节点为黑色。

  3、如果节点为红,子节点必须为黑。

  4、任意节点至树尾端的任何路径,黑节点必须相同。

  

规则4主要是保证树的平衡性,不过它的要求不是很严。主要是为了减少调整操作。根据规则4,我们可以判断出新节点都是红节点。(如果新节点是黑节点,那么每次插入都要进行调整)

由于要经常使用某个节点的父亲。所以这里添加了一个指向父亲的指针。所以我们先看一下红黑树的结构组成。

typedef int value_type;
typedef bool color_type;
const color_type red = true;
const color_type black = false;

typedef struct node
{
    value_type value;
    color_type color;

    struct node * parent;
    struct node * left;
    struct node * right;
} Node;

typedef struct Tree
{
    Node * root;
} Tree;

Node节点,value,关键字信息。color,颜色。parent,left,right,父亲,左孩子,右孩子。

Tree只有一个根节点。

插入操作,与二叉树的插入是一样的。

首先是找到插入位置。

//根节点返回NULL,找到返回当前节点,否则返回x的父亲(x是节点所在的位置)
static Node * search_node(const int key, Tree * tree)
{
    Node * x, * y;

    x = tree->root;
    y = nil;

    while ( x != nil )
    {
        y = x;
        if ( key < x->value )
            x = x->left;
        else if ( key >  x->value )
            x = x->right;
        else
            break;
    }

    return y;
}

nil是一个空节点,所有应该为空的指针都指向它。这个节点是黑色的,parent,left,right都为NULL,没有初始化value。(不是一定要有nil节点)

其次将元素插入

void rb_insert(const value_type value, Tree * tree)
{
    Node * new_node;//新节点
    Node * x = search_node(value, tree);//插入点

    if ( x == nil )
    {
        tree->root = make_new(value);
        tree->root->color = black;//根节点为黑色
    }
    else
    {
        if ( x->value == value )//关键字不可重复
            return;

        new_node = make_new(value);
        if ( value < x->value )//将新节点插入二叉树中
            x->left = new_node;
        else
            x->right = new_node;
        new_node->parent = x;//设置新节点的父亲

        if ( x->color == red )//如果新节点的父亲为红色,调整
            insert_fixup(new_node, tree);
    }
}

新节点一定是红色的,所以不会违反规则4,但有可能违反规则3。也就是说如果插入节点的父亲是红色的,那么违反了规则3。

我们需要进行调整。

调整时会遇到三种情况,根据不同的情况进行不同的调整。

调整是一个循环过程,当x为根节点或者x是黑色时结束。(这个操作次数并不会很多)

三种情况在代码中看注释。

static void insert_fixup(Node * x, Tree * tree)
{
    Node * y;//y是x的伯父节点
    while ( x != tree->root && x->parent->color == red )
    {
        if ( x->parent == x->parent->parent->left )//父亲是祖父左孩子
        {
            y = x->parent->parent->right;

            //case 1:    伯父是红色
            //处理办法
            //        1.将父亲,伯父变成黑色
            //        2.将祖父变成红色
            //        3.将祖父设为x,向上检查
            if ( y->color == red )
            {
                x->parent->color = black;
                y->color = black;
                x->parent->parent->color = red;
                x = x->parent->parent;
            }
            else
            {
                //case 2:    x是父亲的右孩子
                //处理办法:
                //        1.将x设为x的父亲
                //        2.以x为旋转点,左旋
                //经过上述操作,转换成case 3
                if ( x == x->parent->right )
                {
                    x = x->parent;
                    left_rotate(x, tree);
                }

                //case 3:    x是父亲的左孩子
                //处理办法:
                //        1.将x的父亲设为黑色
                //        2.将x的祖父设为红色
                //        3.以x的祖父为旋转点,右旋
                x->parent->color = black;
                x->parent->parent->color = red;
                right_rotate(x->parent->parent, tree);
            }
        }
        else//与上述处理相同,只是将left与right互换
        {
            y = x->parent->parent->left;

            if ( y->color == red )
            {
                x->parent->color = black;
                y->color = black;
                x->parent->parent->color = red;
                x = x->parent->parent;
            }
            else
            {
                if ( x == x->parent->left )
                {
                    x = x->parent;
                    right_rotate(x, tree);
                }

                x->parent->color = black;
                x->parent->parent->color = red;
                left_rotate(x->parent->parent, tree);
            }
        }
    }//while end

    tree->root->color = black;
}

这样插入操作就完成了。

这是一棵红黑树,圆圈里的代表黑色节点,没有圆圈的代表红色。大家可以利用这棵树来调代码。建议在调整时,用printf把case 1到3标记一下,挨个试验。

这颗树的插入顺序是10,7,8,15,5,6,11,13,12。

时间: 2024-10-16 16:55:33

红黑树(二)插入的相关文章

红黑树的插入和删除

一.红黑树的简介 红黑树是一种平衡的二叉查找树,是一种计算机科学中常用的数据结构,最典型的应用是实现数据的关联,例如map等数据结构的实现. 红黑树有以下限制: 1. 节点必须是红色或者是黑色 2. 根节点是黑色的 3. 所有的叶子节点是黑色的. 4. 每个红色节点的两个子节点是黑色的,也就是不能存在父子两个节点全是红色 5. 从任意每个节点到其每个叶子节点的所有简单路径上黑色节点的数量是相同的. 要说明一下限制3.一般在红黑树中,每个节点空指针处还会加空的黑色的孩子(称为岗哨).所以限制3一定

红黑树之插入

1.红黑树 (1).概念 i>每个结点不是红的就是黑的: ii>根结点为黑的: iii>红结点的孩子必为黑结点: iv>(除了根结点)任一结点不管通过什么路径,到达叶子节点的黑结点数目一定相同: 总结概括:一头一脚黑,黑同红不连:根为黑,到脚(叶子节点)的黑结点相同,红结点不相连: 2.递归--->一般先写if结束语句 化非递归------>用while()循环和栈; enum{RED, BLACK}; 这个枚举是有值得,分别为0.1: 3.红黑树与AVL树  AVL树

红黑树的插入与删除

红黑树(Red Black Tree) 是一种自平衡二叉查找树.红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能.红黑树可以在O(log n)时间内完成查找,插入和删除操作. 二叉搜索树可以看 二叉搜索树 AVL树可以看 AVL树的插入与删除 1. 红黑树的性质 红黑树的自平衡依赖于它的以下性质: 性质1. 结点是红色或黑色. 性质2. 根结点是黑色. 性质3. 每个结点节点(NIL结点,空结点,与其它二叉搜索树不同,红黑树将叶子结点的孩子

红黑树从头至尾插入和删除结点的全程演示图

红黑树插入和删除结点的全程演示 作者:July.saturnman.时间:二零一一年三月二十八日.出处:http://blog.csdn.net/v_JULY_v.声明:版权所有,侵权必究.----------------------------------- 引言: 目前国内图书市场上,抑或网上讲解红黑树的资料层次不齐,混乱不清,没有一个完整而统一的阐述.而本人的红黑树系列四篇文章(详见文末的参考文献),虽然从头至尾,讲的有根有据,层次清晰,然距离读者真正做到红黑树了然于胸,则还缺点什么. 而

红黑树的插入和遍历时间复杂度分析

红黑树的插入和遍历时间复杂度分析 在平常的工作中,最常用的一种数据结构恐怕是std::map了.因此对其的时间复杂度分析是有必要的,编写程序时做到心中有底. 一.理论分析 在stl中std::map和std::set都采用红黑树的方式实现.我们知道插入一个元素到红黑树的时间为log(N),其中N为当前红黑树的元素个数,因此,采用插入方式构建元素个数为N的红黑树的时间复杂度为: log(1) + log(2) + log(N-1) = log((N-1)!) = Nlog(N) 那么采用迭代器遍历

红黑树的插入

一.红黑树的介绍 先来看下算法导论对R-B Tree的介绍: 红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black.通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的. 前面说了,红黑树,是一种二叉查找树,既然是二叉查找树,那么它必满足二叉查找树的一般性质.下面,在具体介绍红黑树之前,咱们先来了解下 二叉查找树的一般性质:1.在一棵二叉查找树上,执行查找.插入.删除等操作,的时间复杂度为O(

红黑树(2) - 插入操作

1.插入介绍 首先以二叉排序树的方法增加节点并标记它为红色.(为何不是红色?因为如果设为黑色,就会导致根到叶子的所有路径中,有一条路径上会多出一个额外的黑节点,这个是很难调整的).但是,设为红色节点后,可能会导致出现两个连续红色节点的冲突,则可以通过重新着色和旋转来调整.具体的调整操作取决于其他临近节点的颜色. 下面分析一下插入新节点后可能对红黑树性质产生的影响: 性质1-节点是红色或黑色.和性质3-所有叶子都是黑色.这两条总是可以维持不变. 性质4-每个红色节点的两个子节点都是黑色.只在增加红

图解集合7:红黑树概念、红黑树的插入及旋转操作详细解读

原文地址http://www.cnblogs.com/xrq730/p/6867924.html,转载请注明出处,谢谢! 初识TreeMap 之前的文章讲解了两种Map,分别是HashMap与LinkedHashMap,它们保证了以O(1)的时间复杂度进行增.删.改.查,从存储角度考虑,这两种数据结构是非常优秀的.另外,LinkedHashMap还额外地保证了Map的遍历顺序可以与put顺序一致,解决了HashMap本身无序的问题. 尽管如此,HashMap与LinkedHashMap还是有自己

红黑树、插入删除操作

二叉排序树 一棵自平衡的二叉排序树(二叉搜索树) 生成二叉排序树的过程是非常容易失衡的,最坏的情况就是一边倒(只有右/左子树),这样会导致二叉树的检索效率大大降低(O(n)). 为了维持二叉树的平衡,有各种的算法,如:AVL,SBT,伸展树,TREAP ,红黑树等等. 红黑树 红黑树需要满足5条性质: - 节点非红即黑 - 根节点是黑色 - 所有NULL结点称为叶子节点,且认为颜色为黑 - 所有红节点的子节点都为黑色,一条路径上不能出现相邻的两个红色结点 - 从任一节点到其叶子节点的所有路径上都

红黑树的插入操作

1 package Tree; 2 3 import org.junit.Test; 4 5 class RedBlackTreeNode { 6 7 int key = 0; 8 RedBlackTreeNode left = null; 9 RedBlackTreeNode right = null; 10 RedBlackTreeNode parent = null; 11 // 色域,0表示黑色,1表示红色 12 int color; 13 14 public RedBlackTreeN