红黑树知识介绍

1.红黑树介绍

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是 计算机科学中用到的 一种数据结构,典型的用途是实现 关联数组
它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。

红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

注意
(01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
(02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。

2.红黑树的应用

    红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。

例如,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。

3.左旋


/* * 对节点(x)进行左旋转
* 左旋示意图:
*           px                     px
*          /                       /
*         x                       y
*        / \       --(左旋)-->   / \     
*      lx   y                   x   ry 
*          / \                 / \
*         ly  ry             lx   ly              
*/
void LeftRotate(RBTNode*& root, RBTNode* x)
{
    /*设置x的右孩子节点为y*/
    RBTNode* y = x->right;
    x->right = y->left;
    if(NULL != y->left)
        y->left->parent = x;
     y->parent = x->parent;
    if(NULL == x->parent)
        root = y;
    else{
        if(x = x->parent->left)
            x->parent->left = y;
        else
            x->parent->right = y;
     }
    y->left = x;
    x->parent = y;
}

4.右旋

                      

/* 
 * 对红黑树的节点(y)进行右旋转
 *
 * 右旋示意图(对节点y进行左旋):
 *            py                               py
 *           /                                /
 *          y                                x                  
 *         /  \      --(右旋)-->            /  \                     #
 *        x   ry                           lx   y  
 *       / \                                   / \                   #
 *      lx  rx                                rx  ry
 * 
 */
 
 void RightRotate(RBTNode*& root, RBTNode* y)
 {
     RBTNode* x = y->right;
     y->left = x->right;
     if(NULL != x->right)
         x->right->parent = y;
     if(NULL == y->parent)
         root = x;
     else{
         if(y == y->parent->left)
             y->parent->left = x;
         else
             y->parent->right = x;
     }
     x->parent = y->parent;
     y->parent = x;
 }

5.   插入节点
红黑树添加节点分三步完成
第一:将红黑树当作一颗二叉树,插入新节点
    红黑树本身就一颗二叉树,在插入新节点后仍旧是一颗有序的二叉树
第二:将插入节点设置为红色,为什么?

    回忆下红黑树的5个特性,插入新节点后有没有违背5个特性 ,应该尽量少违背这些特性,设置为红色不会违背特性5,而设置为黑色则要多违背一条特性5,因此设置为红色
第三:进行旋转和重新着色,使之重新成为一颗红黑树,插入操作可能会违背特性4( 如果一个节点是红色的,则它的子节点必须是黑色的
//root为红黑树跟节点,node为需要插入的节点
void InsertNode(RBTNode*& root, RBTNode* node)
{
    RBTNode* p=NULL;
    RBTNode* cur=root;
    while(NULL != cur){
        p = cur;
        if(node->key < cur->key)
            cur = cur->left;
        else
            cur = cur->right;
    }
    node->parent = p;
    if(NULL != p){
        if(p->key > node->key)
            p->left = node;
        else
            p->right = node;
    }
    root = node;
    node->color = RED;
    InsertFix(root, node);
}

void InsertFix(RBTNode*& root, RBTNode* node)
{
    RBTNode* parent, gparent,uncle;
    while(node->parent && node->parent->color == RED){
        parent = node->parent;
        gparent = parent->parent;
        /*父节点是祖父节点的左孩子,则叔父节点为祖父节点的右孩子*/
        if(parent == gparent->left){
            uncle = gparent->right;
            if(uncle->color == RED){
                set_node_color_black(parent);
                set_node_color_black(uncle);
                set_node_color_red(gparent);
                node = gparent;
                continue;
            }
            /*叔叔节点是黑色*/
            else{
            	    /*当前接点为右孩子*/
                	if(node == parent->right){
                	    LeftRotate(root, parent)
                	    RBTNode* tmp = p;
                	    p = node;
                	    node =tmp;	
                	}/*当前接点为左孩子*/
                	else{
                	    set_node_color_black(parent);
                	    set_node_color_red(gparent);
                	    RightRotate(root, gparent);	
                	}
            }
        }
        /*父节点是祖父节点的右孩子*/
        else{
            uncle = gparent->left;
            /*叔叔节点是红色*/
            if(uncle->color == RED){
                set_node_color_black(uncle);	
                set_node_color_black(parent);
                set_node_color_red(gparent);
                node = gparent;
                continue;
            }
            /*叔叔节点为黑色,则祖父一定是黑色*/
            else{
            	  /*当前节点为右孩子*/
                if(node == parent->right){
                    set_node_color_black(parent);
                    set_node_color_red(gparent);
                    LeftRotate(root, gparent)
                }
                /*当前节点为左孩子*/
                else{
                    RightRotate(root, parent);
                    RBTNode* tmp = parent;
                    parent = node;
                    node = tmp;	
                }
            }
        }
    }
    /*走到这里:
     *情况1:入节点即跟节点,则直接设置为黑色
     *情况2:或者插入节点的父节点为黑色,原本根节点就是黑色,相当于啥也不做
     *情况3:一番左右旋后把根节点设置为黑色*/
    set_node_color_black(root);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值