红黑树

弄了很久,学习过程中觉得很难,但学完了,其实感觉也就那样,就是情况多了些。

首先是插入,插入的时候其实也就3种情况,因为只有当插入的节点的父亲是红色的时候,此时红黑树的性质遭到破坏,需要旋转,再分1.叔父节点为红,此时只要改变颜色,但祖父节点颜色的改变可能会破坏红黑树的性质,所以要node = grandparent,继续向上,叔父为黑,这时需要旋转,所以得判断,自身的位置,也就是自己和父亲分别是左孩子还是右孩子,2.如果自身是右,父亲是左,的先把自己也旋转到左,再和自己是左,父亲也是左的情况一起处理,即再进行一次旋转,旋转其实只要是为了满足根节点到叶子节点的黑色节点数这一性质(其实是在减小树的深度),颜色的改变一是配合旋转,二是满足些别的性质,3.自身是左,而父亲是右也就是差不多的了。

另外就是删除,删除就很麻烦一些了,首先是要找到要删除节点的右孩子的最左儿子(左右儿子都存在的情况下)来替代,左儿子不存在直接用右儿子替代,右儿子不存在直接用左儿子替代,都不存在则用空节点替代,另外记录下替代节点的孩子和替代节点的父亲(如果删除节点只有一个孩子,替代节点的孩子就是替代节点),然后把孩子指向父亲,只记一个node是不行的,因为node可能为空,当替代点的颜色是黑色的话,需要另外平衡,平衡中如果替代节点的孩子是红色,直接改成黑色就OK了(因为之前只是少了个黑色节点,而红改黑除了改变黑色节点的个数外是不改变别的性质的),当替代节点孩子是黑色时,再分其兄弟节点的颜色1.兄弟节点是红色,此时改变颜色,单步旋转(因为兄弟节点所在的枝黑色节点只比另一边多一);然后如果兄弟节点是黑色2.兄弟节点的两个孩子也是黑色或者是空,此时只需改变颜色,但父亲颜色的改变可能会破坏树的性质则node = grandparent,向上继续传,来平衡3.兄弟节点有一个红,此时又得确定位置,父亲是左孩子,而自己是右孩子黑色或空,又得先把黑色的旋转到和父亲相同的相对位置,4然后转到父亲和自己都是左孩子情况,一步旋转。父亲是右孩子的情况也一样。

自己写上面的删除和插入的时候自己都感觉晕晕的,感觉了解的还不是很彻底,改天得再写一遍。。。

#include <iostream>
#include <cstdio>
using namespace std;

#define red 0
#define black 1

template <class T>
class  red_black_node
{
    public:
    red_black_node* left;
    red_black_node* right;
    red_black_node* parent;
    T key;
    int color;
    red_black_node(T value):left(NULL),right(NULL),parent(NULL),color(red),key(value){};
    red_black_node(T value,red_black_node* l,red_black_node* r,red_black_node* p):
        left(l),right(r),parent(p),T(value),color(red){};
};

template <class T>
class red_black_tree
{
public:
   red_black_node<T>* mRoot;//根节点
public:
    red_black_tree();
    ~red_black_tree();
    void Destory(red_black_node<T>* Pnode);
    red_black_node<T>* RotateLeft(red_black_node<T>* p,red_black_node<T>* r);
    red_black_node<T>* RotateRight(red_black_node<T>* p,red_black_node<T>* r);
    red_black_node<T>* Insert_into(T k,red_black_node<T>* root);
    void Insert(T k);
    red_black_node<T>* Search(T k,red_black_node<T>* root);
    red_black_node<T>* Insert_balance(red_black_node<T>* node,red_black_node<T>* root);
    void Travel_it(red_black_node<T> *root);
    void Trave();

    red_black_node<T>* Delete_Replace(T k,red_black_node<T>* root);
    void Delete(T k);
    red_black_node<T>* Delete_balance(red_black_node<T>* child,red_black_node<T>* parent,red_black_node<T>* root);
};

//左旋函数,并未改变颜色
template <class T>
red_black_node<T>* red_black_tree<T>::RotateLeft(red_black_node<T>* node,red_black_node<T>* root)
{
    red_black_node<T>* tem = node->left;
    node->left = tem->right;
    tem->right = node;
    tem->parent = node->parent;
    node->parent = tem;
    if(node->left!=NULL)
    node->left->parent = node;

    if(tem->parent==NULL)
    {
        root = tem;
    }
    else
    {
        if(tem->key > tem->parent->key)
        {
            tem->parent->right = tem;
        }
        else
        {
            tem->parent->left = tem;
        }
    }
    return root;
}

//构造函数
template <class T>
red_black_tree<T>::red_black_tree()
{
    mRoot = NULL;
}

//析构函数
template <class T>
red_black_tree<T>::~red_black_tree()
{
    Destory(mRoot);
}

//单步右旋
template <class T>
red_black_node<T>* red_black_tree<T>::RotateRight(red_black_node<T>* node,red_black_node<T>* root)
{

    red_black_node<T>* tem = node->right;
    node->right = tem->left;
    tem->left = node;
    tem->parent = node->parent;
    node->parent = tem;
    if(node->right!=NULL)
    node->right->parent = node;

    if(tem->parent==NULL)
    {
        root = tem;
    }
    else
    {
        if(tem->parent->key > tem->key)
        {
            tem->parent->left = tem;
            //red_black_tree<T>::Travel_it(root);
        }
        else
        {
            tem->parent->right = tem;
        }

    }
    return root;
}

//销毁红黑树
template <class T>
void red_black_tree<T>::Destory(red_black_node<T>* PnodeHeader)
{
    if(PnodeHeader==NULL)
        return ;
    if(PnodeHeader->left!=NULL)
        Destory(PnodeHeader->left);
    if(PnodeHeader->right!=NULL)
        Destory(PnodeHeader->right);
    delete PnodeHeader;
}

template <class T>
void red_black_tree<T>::Insert(T k)
{
   mRoot =  Insert_into(k,mRoot);
}

template <class T>//返回的是自己或者是自己的父亲
red_black_node<T>* red_black_tree<T>::Search(T k,red_black_node<T>* root)
{
    red_black_node<T>* tem = root;
    if(tem==NULL)return NULL;
    while(true)
    {
        if(k<tem->key)
        {
            if(tem->left==NULL)return tem;
            else tem = tem->left;
        }
        else if(k>tem->key)
        {
            if(tem->right==NULL)return tem;
            else tem = tem->right;
        }
        else
        return tem;
    }
}

template <class T>
red_black_node<T>* red_black_tree<T>::Insert_into(T k,red_black_node<T>* root)
{
    red_black_node<T>* node;
    red_black_node<T>* tem = Search(k,root);

    //if(tem->key==k)return root;//重复直接退出
    node = new red_black_node<T>(k);
    node->parent = tem;
    if(tem)
    {
        if(tem->key > k)
        {
            tem->left = node;
        }
        else
        {
            tem->right = node;
        }
    }
    else
    {
        root = node;
    }
    //red_black_tree<T>::Trave();
    return Insert_balance(node,root);
}

template<class T>
red_black_node<T>* red_black_tree<T>::Insert_balance(red_black_node<T>* node,red_black_node<T> *root)
{
    red_black_node<T> *p,*gp,*uncle,*tem;
    while((p=node->parent)&&p->color==red)
    {
        gp = p->parent;
        if(p==gp->left)
        {
            uncle = gp->right;
            if(uncle&&uncle->color==red)//1.父亲节点和叔父节点都为红
            {
                uncle->color = black;//
                p->color = black;
                gp->color = red;
                node = gp;
            }
            else
            {
                if(p->right==node)//2.叔父节点为黑,或者不存在,自己是右孩子,父亲是左孩子
                {
                    root = RotateRight(p,root);

                    tem = p;
                    p = node;
                    node = tem;
                }

                p->color = black;
                gp->color = red;

                root = RotateLeft(gp,root);
            }
        }
        else
        {
            uncle = gp->left;
            if(uncle&&uncle->color==red)
            {
                uncle->color = black;
                p->color = black;
                gp->color = red;
                node = gp;
            }
            else
            {

                    if(p->left==node)
                    {
                        root = RotateLeft(p,root);
                        tem = p;
                        p = node;
                        node = tem;
                    }
                    p->color = black;
                    gp->color = red;
                    root = RotateRight(gp,root);

            }
        }
    }
    root->color = black;
    return root;
}

//打印函数
template <class T>
void red_black_tree<T>::Travel_it(red_black_node<T> *root)
{
    if(root==NULL)return;
    printf("father is:%d",root->key);
     if(root->color==red)printf("(red)");
        else printf("(black)");
    printf(" left:");
    if(root->left==NULL)printf("NULL");
    else
    {
        printf("%d",root->left->key);
        if(root->left->color==red)printf("(red)");
        else printf("(black)");
    }
    printf(" right:");
    if(root->right==NULL)printf("NULL\n");
    else
    {
        printf("%d",root->right->key);
       if(root->right->color==red)printf("(red)\n");
        else printf("(black)\n");
    }
    Travel_it(root->left);
    Travel_it(root->right);
}

template <class T>
void red_black_tree<T>::Trave()
{
    Travel_it(mRoot);
}

template <class T>//左右子树都不空时用右孩子的最左子树来替代,左子树为空,直接用右孩子替代,右子树为空直接用左孩子替代
red_black_node<T>* red_black_tree<T>::Delete_Replace(T k,red_black_node<T>* root)
{
    red_black_node<T> *tem;
    tem = red_black_tree<T>::Search(k,mRoot);
    if(tem==NULL)return mRoot;
    if(tem->key!=k)
    {
        printf("The Key Is Wrong\r\n");
        return mRoot;
    }
    red_black_node<T>* aim = tem;
    red_black_node<T>* replace_parent;
    red_black_node<T>* replace_child;
    int color;
    if(tem->left&&tem->right)
    {
        tem = tem->right;
        while(tem->left!=NULL)
        {
            tem = tem->left;
        }
        replace_parent = tem->parent;
         replace_child  = tem->right;
         color = tem->color;
        if(replace_child)
        {
            replace_child->parent = replace_parent;
        }
        if(replace_parent)
        {
            if(tem->key < replace_parent->key)
            {
                replace_parent->left = replace_child;
            }
            else
            {
                replace_parent->right = replace_child;
            }
        }
        else//??
        {
            root = replace_child;
        }
        //??
        if (tem->parent == aim)
        {
            replace_parent = tem;
        }
        tem->parent = aim->parent;

        tem->left = aim->left;

            tem->right = aim->right;
        tem->color = aim->color;

        if(aim->parent)
        {
            if(tem->key < aim->parent->key)
            {
                tem->parent->left = tem;
            }
            else
            {
                tem->parent->right = tem;
            }
        }
        else
        {
            root = tem;
        }
        aim->left->parent = tem;
        if(aim->right)
        {
            aim->right->parent = tem;
        }
    }
    else
    {
        if(!tem->left)
        {
            replace_child = tem->right;
        }
        else if(!tem->right)
        {
            replace_child = tem->left;
        }
        replace_parent = tem->parent;
        color = tem->color;
        if(replace_child)
        {
            replace_child->parent = replace_parent;
        }
        if(replace_parent)
        {
            if(replace_parent->left==tem)
            {
                replace_parent->left = replace_child;
            }
            else
            {
                replace_parent->right = replace_child;
            }
        }
        else
        {
            root = replace_child;
        }
    }
    delete aim;
    if(color==black)
    {
        root = Delete_balance(replace_child,replace_parent,root);
    }
    return root;
}

template <class T>
void red_black_tree<T>::Delete(T k)
{
    mRoot = Delete_Replace(k,mRoot);
}

template <class T>//替代的节点是黑色时的旋转平衡
red_black_node<T>* red_black_tree<T>::Delete_balance(red_black_node<T>* child,red_black_node<T>* parent,red_black_node<T>* root)
{
   red_black_node<T> *other, *o_left, *o_right;
   while((!child||child->color==black)&&child!=root)
   {
       if(parent->left==child)//是左孩子,只能是,之前用删除节点的左孩子替代
       {
           other = parent->right;
           if(other->color==red)
           {
               other->color = black;//兄弟节点是红色
               parent->color = red;
               root = RotateRight(parent,root);//旋转下即可
               other = parent->right;
           }
           //x的兄弟是黑色的,且两个孩子也是黑色的
            if ((!other->left || other->left->color == black) &&
                (!other->right || other->right->color == black))
                {
                    other->color = red;
                    child = parent;
                    parent = child->parent;
                }
                else
                {
                    if(!other->right||other->right->color==black)
                    {
                        if(o_left = other->left)
                        {
                            o_left->color = black;
                        }
                        other->color = black;
                        root = RotateLeft(other,root);
                        other = parent->right;
                    }
                    //x的兄弟是黑色的
                    other->color  = parent->color;
                    parent->color = black;
                    if(other->right)
                    {
                        other->right->color = black;
                    }
                    root = RotateRight(parent,root);
                    child = root;
                    break;
                }
       }
       else
       {
           other = parent->left;
           if(other->color==red)
           {
               other->color  = black;
               parent->color = red;
               root = RotateLeft(parent,root);
               other = parent->left;
           }
           if((!other->left||other->left->color==black)&&(!other->right||other->right->color==black))
              {
                  other->color = red;
                  child = parent;
                  parent = child->parent;
              }
              else
                {
                    if(!other->left||other->left->color==black)
                    {
                        if(o_right = other->right)
                        {
                            o_right->color = black;
                        }
                        other->color = red;
                        root  = RotateRight(other,root);
                        other = parent->left;
                    }
                    other->color = parent->color;
                    parent->color = black;
                    if(other->left)
                    {
                        other->left->color = black;
                    }
                    root = RotateLeft(parent,root);
                    child = root;
                    break;
                }
       }
   }
   if(child)
   {
       child->color = black;
   }
   return root;
}

int main()
{
    int a[] = {15,7,10,9,4,5,8,20,1,6};
    red_black_tree<int>* tree = new red_black_tree<int>();
    red_black_node<int> *root = NULL;

    for(int i=0;i<sizeof(a)/sizeof(int);i++)
    {
       tree->Insert(a[i]);
       //tree->Find_parent();
      // tree->Trave();
      // getchar();
    }
        tree->Trave();
        printf("\n");
    for(int i=0;i<sizeof(a)/sizeof(int);i++)
    {
        tree->Delete(a[i]);
        tree->Trave();
        getchar();
    }
    return 0;
}

时间: 2024-08-01 22:47:26

红黑树的相关文章

B树、B+树、红黑树、AVL树比较

B树是为了提高磁盘或外部存储设备查找效率而产生的一种多路平衡查找树. B+树为B树的变形结构,用于大多数数据库或文件系统的存储而设计. B树相对于红黑树的区别 在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况.为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,接着旋转盘面找到数据所在的磁道,最后对数据进行读写.磁盘IO代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读

红黑树之删除节点

红黑树之删除节点 上一篇文章中讲了如何向红黑树中添加节点,也顺便创建了一棵红黑树.今天写写怎样从红黑树中删除节点. 相比于添加节点,删除节点要复杂的多.不过我们慢慢梳理,还是能够弄明白的. 回顾一下红黑树的性质 红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色.在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求: 节点是红色或黑色. 根节点是黑色. 每个叶节点(这里的叶节点是指NULL节点,在<算法导论>中这个节点叫哨兵节点,除了颜色属性外,其他属性值都为任

数据结构与算法-红黑树

前言 红黑树是工程中最常用到的一种自平衡二叉排序树,其和AVL树类似,都是在进行插入.删除时通过一定的调整操作来维持相对稳定的树高,从而获得较好的查询性能. 性质 1. 节点是红色或黑色. 2. 根节点是黑色. 3 每个叶节点(null节点)是黑色的. 4 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的红色节点) 5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点. 维护红黑树形状(树高)的,主要就是4.5两条性质,性质4决定了最长的路径莫过于红黑间隔

数据结构学习笔记-排序/队/栈/链/堆/查找树/红黑树

排序: 插入排序:每次从剩余数据中选取一个最小的,插入已经排序完成的序列中 合并排序:将数据分成左右两组分别排序,然后合并,对每组数据的排序递归处理. 冒泡排序:重复交换两个相邻元素,从a[1]开始向a[0]方向冒泡,然后a[2]...当a[i]无法继续往前挤的时候说明前面的更小了,而且越往前越小(挤得越往前) 堆排序:构造最大堆,每次取走根结点(自然是最大的),再调用MAX-HEAPIFY算法(见后文的堆)恢复最大堆的性质,重复取走根结点 快速排序(对A[r]-A[n]进行排序): 1.从序列

红黑树与AVL(平衡二叉树)的区别

关于红黑树和AVL树,来自网络: 1 好处 及 用途 红黑树 并不追求"完全平衡 "--它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能. 红黑树能够以 O(log2  n)  的时间复杂度进行搜索.插入.删除操作.此外,由于它的设计,任何不平衡都会在三次旋转之内解决.当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较"便宜"的解决方案.红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高

数据结构-红黑树

转自:http://dongxicheng.org/structure/red-black-tree/ 1. 简介 红黑树是一种自平衡二叉查找树.它的统计性能要好于平衡二叉树(AVL树),因此,红黑树在很多地方都有应用.在C++ STL中,很多部分(目前包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持).它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它

定时器管理:nginx的红黑树和libevent的堆

libevent 发生超时后, while循环一次从堆顶del timer——直到最新调整的最小堆顶不是超时事件为止,(实际是del event),但是会稍后把这个timeout的 event放到active 任务list里, 等待处理,event标记为timeout,等处理actvie队列时再由应用层callback函数决定怎么处理标记为timeout的事件. nginx处理超时时,直接删除红黑树中( event结构体里的 )rb node成员,同时调用应用层早已通过add timer注册好的

数据结构——红黑树

红黑树是二叉排序树的改进, 红黑树有几个特点: 1:节点只有2中颜色,红色和黑色. 2:根节点一定是黑色节点. 3:红色节点的子节点一定是黑色节点. 4:黑色高度(根节点到每个叶子节点的路径长度包含相同的黑色节点)相等. 规定的插入的节点一定是红色节点, 红黑树的插入节点后需要调整的规则,插入节点需要调整的情况有3种: 情况1:插入的节点的父节点和叔叔节点都为红色: 以上情况节点4为插入节点(当前节点),这种情况调整方式是将父节点和叔叔节点都调整为黑色节点,祖父节点调整为红色,将祖父节点变为当前

【转】B树、B-树、B+树、B*树、红黑树、 二叉排序树、trie树Double Array 字典查找树简介

B  树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中:否则,如果查询关键字比结点关键字小,就进入左儿子:如果比结点关键字大,就进入右儿子:如果左儿子或右儿子的指针为空,则报告找不到相应的关键字: 如果B树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树的搜索性