红黑树的C++实现

红黑树的C++实现

关于红黑树,可以参考《算法导论》第三版第13章,在CSDN上也有很多文章讲述,在此不再具体讲述。主要说一下自己对红黑树的一些理解。

1.红黑树是平衡树的一种,红黑树不同于AVL树,它牺牲了严格的高度平衡的,只要求局部的达到平衡要求,从而降低了对旋转的要求,提高了性能。严格意义上,红黑树的高度至多为2lg(n+1)

2.在算法导论中,红黑树的实现有一个很重要的一点就是设置了哨兵nil,哨兵的颜色设置为黑色,并且将所有叶节点的左右孩子设置为nil,将根的父节点也设置为nil,这样设计的目的是为了方便插入删除,否则的话需要经常测试是否为根节点,叶子节点,而且对于这些节点的插入删除情况还要和其它节点区分开来。这一点在程序中可以仔细的体悟。
源代码下载地址:http://download.csdn.net/detail/u010772289/9416611
具体C++实现如下:

//RedBlackTree.h
/*
 * 算法导论第13章:红黑树 C++实现
 * 功能:查找find,插入insert,删除erase,最大值max,最小值min 销毁destroy
 * 红黑树性质:
 *  1.节点为红/黑
 *  2.根节点为黑
 *  3.叶节点(nil)均为黑
 *  4.红节点的两个子节点必须为黑
 *  5.每条简单路径黑节点数相同
 */
#include <initializer_list>

#ifndef __REDBLACKTREE_H__
#define __REDBLACKTREE_H__


class RedBlackTree{
private:
    struct Node;
public:
    typedef Node *Position, *RBTree;
    enum Color{ RED = 0, BLACK };
public:
    using ElemmentType = int;
    RedBlackTree();
    RedBlackTree(const std::initializer_list<ElemmentType>&);  //列表初始化
    ~RedBlackTree();

    Position max(RBTree T);
    Position min(RBTree T);
    Position max(){ return max(root); }
    Position min(){ return min(root); }
    Position find(ElemmentType X); //查找
    void insert(ElemmentType X);
    void erase(ElemmentType X);
    void destroy();  //销毁
    void PrintRBTree();

    ElemmentType key(Position P){ return  P->key; }
    Color color(Position P){ return P->color; }
    Color color(ElemmentType X){ Position P = find(X); return color(P); }
    Position left(Position P){ return P->left; }
    Position right(Position P){ return P->right; }
    Position parent(Position P){ return P->parent; }

private:
    RBTree root;  //根节点
    RBTree nil;   //哨兵

    void insert_fixup(Position z);
    void left_rotate(RBTree T);  // 左旋
    void right_rotate(RBTree T);  //右旋
    void destroy(RBTree T);
    void RB_TransPlant(RBTree x, RBTree y);  //以子树y替换子树x
    void RB_Delete_Fixup(Position x);  //删除黑色节点后,重新调整红黑树
    void PrintRBTree(RBTree T);

    static const ElemmentType UnInfinity = -65535;
    struct Node{
        Node()=default;
        Node(ElemmentType _key, Node* _left, Node* _right,Node* _parent, Color _clolor) 
            :key(_key),left(_left),right(_right),parent(_parent),color(_clolor){}
        //~Node();
        ElemmentType key=UnInfinity;
        Node* left=nullptr;  //左孩子
        Node* right=nullptr;  //右孩子
        Node* parent=nullptr;      //父节点
        Color color = RED;      //颜色,默认为红
    };
};

#endif  //RedBlackTree.h
#include <stdexcept>
#include <iostream>
#include "RedBlackTree.h"

using std::initializer_list;

RedBlackTree::RedBlackTree() :nil(new Node())
{   
    nil->color = BLACK;
    root = nil;
}


RedBlackTree::RedBlackTree(const initializer_list<ElemmentType>& il) :nil(new Node())
{
    nil->color = BLACK;
    root = nil;
    for (initializer_list<ElemmentType>::const_iterator it = il.begin(); it != il.end(); ++it)
        insert(*it);
}

RedBlackTree::~RedBlackTree()
{
    destroy();
}

RedBlackTree::Position RedBlackTree::max(RBTree T)
{
    Position p=T;
    if (p!=nil)
    while (p->right != nil)
        p = p->right;
    return p;
}

RedBlackTree::Position RedBlackTree::min(RBTree T)
{
    Position p = T;
    if (p != nil)
    while (p->left != nil)
        p = p->left;
    return p;
}

RedBlackTree::Position RedBlackTree::find(ElemmentType X)
{
    Position P = root; 
    while (P != nil){
        if (P->key < X)
            P = P->right;
        else if (P->key>X)
            P = P->left;
        else
            break;
    }
    return P;
}

void RedBlackTree::insert(ElemmentType X)
{
    Position P = root;
    Position lastP = nil;
    while (P != nil ){
        lastP = P;
        if (P->key < X)
            P = P->right;
        else if (P->key>X)
            P = P->left;
        else
            break;
    }
    if (P == nil){   // X不存在于红黑树中时
        Position tmp;
        tmp = new Node();   //新节点
        tmp->key = X;
        tmp->parent = lastP; //设置新节点父亲,根节点父亲设为nil
        tmp->left = tmp->right = nil;
        if (lastP == nil){  //设置根节点
            tmp->color = BLACK;  //根节点必须为黑色
            root = tmp;
        }
        else if (X < lastP->key)  //插入
            lastP->left = tmp;
        else
            lastP->right = tmp;
        if (lastP != nil && lastP->color == RED)  //新插入节点父亲若为红色,则需要调整
            insert_fixup(tmp);
    }
}

/*
 * insert_fixup:插入的新节点父亲为红时进行调整
 * 时间:O(lgN),只有在情况1 while 循环才会重复执行
 * 左子树三种情况:
 *   1.z的叔节点是红色   解决:z上移
 *   2.z的叔节点是黑色且z为右孩子  解决:转为情况3
 *   3.z的叔节点是黑色且z为左孩子  
 * 右子树类似
 */

void RedBlackTree::insert_fixup(Position z)
{
    while (z->parent->color == RED){   //红节点的父亲为黑色时停止(注意:哨兵nil的颜色为黑色)
        if (z->parent == z->parent->parent->left){  //左子树
            if (z->parent->parent->right->color == RED){  //情况1
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                z->parent->parent->right->color = BLACK;
                z = z->parent->parent;  //z上移,设置新的z
            }
            else{
                if (z == z->parent->right){   //情况2
                    z = z->parent;
                    left_rotate(z);
                } 
                z->parent->color = BLACK;//情况3
                z->parent->parent->color = RED;
                right_rotate(z->parent->parent);
            }
        }
        else{  //右子树
            if (z->parent->parent->left->color == RED){    //情况1
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                z->parent->parent->left->color = BLACK;
                z = z->parent->parent;   //上移
            }
            else {
                if (z == z->parent->left){  //情况2
                    z = z->parent;
                    right_rotate(z);
                }
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                left_rotate(z->parent->parent);
            }
        }
    }
    root->color = BLACK;
}

void RedBlackTree::RB_TransPlant(RBTree x, RBTree y)  //以子树y替换子树x
{
    if (x->parent == nil)  //若x为根节点
        root = y;
    else if (x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;
    y->parent = x->parent;   //y为nil时也设置了其父节点
}

void RedBlackTree::erase(ElemmentType X)
{
    Position p = find(X);
    Position x=nil;   //待删除的节点的下一点
    Color cl = p->color;   //cl记录待删除节点的颜色
    if (p == nil)
        throw std::runtime_error("The elemment does not exit!");
    if (p->left == nil){
        x = p->right;   //p为待删除点,x为其下一点
        RB_TransPlant(p, p->right);
    }
    else if (p->right == nil){
        x = p->left;
        RB_TransPlant(p, p->left);
    }
    else {
        Position y = min(p->right);
        cl = y->color;
        RB_TransPlant(y, y->right);
        RB_TransPlant(p, y);

        y->left = p->left;
        y->right = p->right;
        y->left->parent = y;
        //if (y->right != nil)
        y->right->parent = y;
    }
    //x->parent = p->parent;   /// http://www.2cto.com/kf/201307/229160.html
    delete p;
    //PrintRBTree();
    if (cl == BLACK) //若删除了黑色节点,调整红黑树
        RB_Delete_Fixup(x);
}

/*
 * RB_Delete_Fixup: 删除黑色节点后的调整工作
 * 左子树,四种情况:
 *   1.x的兄弟节点为红色  解决:转为情况2,3,4
 *   2.x的兄弟节点w为黑色,w的两个子节点都是黑色的   解决:x,w各去掉一层黑色,将x.p添加一层黑色,x上移
 *   3.x的兄弟节点w为黑色,w的右孩子是黑色的,左孩子是红色的  解决:转为情况4
 *   4.x的兄弟节点w为黑色,w的右孩子红色的      解决:右旋,结束
 * 右子树类似
*/


/*
无论哪种情况删除的都是结点z,而y代表了被“删除”的结点的位置,无论y是z本身还是z的后继结点,
y原来位置的结点都被删除或者移走了了,而x则代表了取代y位置结点的那个结点
(x结点可以是哨兵结点nil,这时nil就体现了它作为哨兵结点的作用,因为nil->p=y,指向了被“删除”结点的位置),
被删除的结点y为黑色,那么根结点到x结点的路径(x是nil结点时,也与性质5相吻合)中的黑色结点数目将会减少1
*/

void RedBlackTree::RB_Delete_Fixup(Position x)
{
    Position w = nil;
    while (x != root && x->color == BLACK){  //x为根节点或者为红色时循环停止
        if (x == x->parent->left){   //左子树
            w = x->parent->right;      //
            if (w->color == RED) { //情况1
                x->parent->color = RED;
                w->color = BLACK;
                left_rotate(x->parent);
                w = x->parent->right;  //更新w
            }
            if (w->left->color == BLACK && w->right->color == BLACK){   //情况2
                w->color = RED;  //x,w去掉一层黑色(w变为红,x由两层黑色变为1层黑色)
                x = x->parent;    //x上移,进行while循环
            }
            else {
                if (w->right->color == BLACK && w->left->color == RED){  //情况3
                    w->color = RED;
                    w->left->color = BLACK;
                    right_rotate(w);
                    w = x->parent->right;
                }
                w->color = x->parent->color; //情况4
                x->parent->color = BLACK;
                w->right->color = BLACK;
                left_rotate(x->parent);
                x = root;   //退出while循环
            }
        }
        else{     //右子树
            w = x->parent->left;
            if (w->color == RED){  //情况1
                w->color = BLACK;
                x->parent->color = RED;
                right_rotate(x->parent);
                w = x->parent->left;
            }
            if (w->left->color == BLACK && w->right->color == BLACK){  //情况2
                w->color = BLACK;
                x = x->parent;
            }
            else {
                if (w->left->color == BLACK && w->right->color == RED){  //情况3
                    w->right->color = BLACK;
                    w->color = RED;
                    left_rotate(w);
                    w = x->parent->left;
                }
                w->color = x->parent->color;    //情况4
                x->parent->color = BLACK;
                w->left->color = BLACK;
                right_rotate(x->parent);
                x = root;
            }
        }
    }
    x->color = BLACK;  ///
}

void RedBlackTree::destroy(RBTree T)
{
    if (T!=nil){
        destroy(T->left);
        delete T;
        destroy(T->right);
    }
}

void RedBlackTree::destroy()  //销毁
{
    destroy(root);
    delete nil;
}

void RedBlackTree::PrintRBTree()
{
    PrintRBTree(root);
}

void RedBlackTree::PrintRBTree(RBTree T)
{
    if (T != nil){
        PrintRBTree(T->left);
        //std::cout << T->key << " : " << T->color << "\t";
        std::cout << T->key << "\t";
        PrintRBTree(T->right);
    }
}

void RedBlackTree::left_rotate(RBTree y)  // 左旋
{
    Position x = y->right;
    y->right = x->left;
    x->parent = y->parent;
    //if (y->right != nil)   //原来y的右孩子未指向哨兵nil,则设置其父亲
    y->right->parent = y;
    if (y->parent == nil){
        //x->parent = nil;
        root = x;
    }
    else if (y == y->parent->left)
        y->parent->left = x;
    else
        y->parent->right = x;
    x->left = y;
    y->parent = x;
}


void RedBlackTree::right_rotate(RBTree x)  //右旋
{
    Position y = x->left;
    x->left = y->right;   //设置x左孩子
    //if (x->left!=nil)     //x左孩子的父亲
    x->left->parent = x;
    y->parent = x->parent;   //设置y
    if (x->parent == nil)    //若原来x为根节点,则设置y为新的根节点
        root = y;
    else if (x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;
    y->right = x;    //连接x,y
    x->parent = y;
}
#include <iostream>
#include "RedBlackTree.h"

using std::cout;
using std::endl;

int main()
{
    RedBlackTree T;
    for (int i = 5; i < 10; ++i)
        T.insert(i);

    for (int i = 5; i < 10; ++i){
        T.erase(i);
        T.PrintRBTree();
        std::cout << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值