红黑树部分实现

红黑树的定义没必要重复了,现在做个简单实现

Color

节点颜色就分两种,定义个枚举最合适了

enum Color { RED, BLACK };

node

节点信息应该有数据data、颜色color、左子节点指针left、右子节点指针right、父节点指针parent(在需要修改树结构的场景,保存父节点指针能省很多事)

template<typename T>
struct Node
{
    T data;
    Color color;
    Node* left;
    Node* right;
    Node* parent;
    Node(T val):data(val),color(RED),left(nullptr),right(nullptr),parent(nullptr){}
};

class

类应该提供基本的插入和删除函数

template<typename T>
class RedBlackTree
{
private:
    Node<T>* root;
    void rotateLeft(Node<T>*& x);
    void rotateRight(Node<T>*& x);
    void insertFix(Node<T>*& x);
    void removefix(Node<T>*& x);
    
public:
    RedBlackTree() : root(nullptr) {}
    ~RedBlackTree();
    void insert(const T& val);
    void remove(const T& val);
    Node<T>* search(const T& val) const;
};

查找

template<typename T>
RedBlackTree<T>::Node* RedBlackTree<T>::search(const T& val)const
{
    Node<T>* x = root;
    while(x != nullptr)
    {
        if(val < x->data)
        {
            x = x->left;
        }
        else if(val > x->data)
        {
            x = x->right;
        }
        else
            break;
    }
    return x;
}

左旋

对A节点做左旋操作,其实是将A节点降为其右子节点的左子节点,如图;中间主要是转移、保存各自父子节点关系
在这里插入图片描述

template <typename T>
void RedBlackTree<T>::rotateLeft(Node<T>*& x)
{
    //获取A右子
    Node<T>* y = x->right;
    //把G设置成A的左子
    x->right = y->left;
    if(y->left != nullptr)//对应的将G父节点指向A
    {
        y->left->parent = x;
    }
    
    //把C的父节点指向A的父节
    y->parent = x->parent;
    if(x == root)//如果A为根,将C设置成新根
    {
        root == y;    
    }
    else if(x == x->parent->left)//如果x是其父节点的左子节点,则设置y为其父节点的左子节点
    {
        x->parent->left = y;    
    }
    else                        //如果x是其父节点的右子节点,则设置y为其父节点的右子节点
    {
        x->parent->right = y;
    }
    
    // 设置y的右子节点为x,并设置x的父节点为y
    y->left = x;
    x->parent = y;
}

右旋

对A节点做右旋操作,其实是将A节点降为其左子节点的右子节点,如图操作,中间需要是转移、保存各自父子节点关系
在这里插入图片描述

template <typename T>
void RedBlackTree<T>::rotateRight(Node<T>*& x)
{
    //获取A左子
    Node<T>* y = x->left;
    //将A左指向F
    x->left = y->right;
    if(y->right != nullptr)//将F父指向A
    {
        y->right->parent = x;    
    }
    //B父指向A父节点
    y->parent = x->parent;
    if(x == root)//如果A是根,将B设置成新根
    {
        root = y;    
    }
    else if(x == x->parent->left)//如果A为左子,将其父节点左子指向B
    {
        x->parent->left = y;    
    }
    else                        //如果A为右子,将其父节点右子指向B
    {
        x->parent->right = y;
    }
    y->right = x;
    x->parent = y;
}

插入修复

插入的新节点都默认设置为红色,不增加黑高。但是可能会破坏红黑树的基本特性,因此要对可能出现的破坏做修复;
操作节点的父节点为黑色,不会破坏红黑树特性无需额外处理;
操作节点的父节点为红色,不符合红黑树的条件,需分情况处理:
1、叔叔节点是红色 即父叔都是红色,处理方式为:将操作节点的父叔节点都染黑,祖父染红,并对祖父节点递归处理;
2、叔叔节点是黑色,父节点为左。处理方式为:如果操作节点x是右子,对父节点左旋,新的x(原父)为左子,将父节点染黑,祖父节点染红后右旋(原x节点升祖父);
3、叔叔节点是黑色,父节点为右。处理方式为:如果操作节点x是左子,将操作父节点右旋,把x处理成右子,将父节点染黑,祖父节点染红后左旋(原x节点升祖父);
如果最后处理到根节点,将根染黑
在这里插入图片描述

template <typename T>
void RedBlackTree<T>::insertFix(Node<T>*& x)
{
    //父节点为红时违反特性,需要修复
    while(x->parent != nullptr && x->parent->color == RED)
    {
        if(x->parent == x->parent->parent->left)//如果操作节点的父节点是左子
        {
            Node<T>* y = x->parent->parent->right;//叔节点
            if(y != nullptr && y->color == RED)//父叔都为红色,则将父叔都染黑,将祖父节点染红(此时祖父这一支高度未变,但是祖父和他父节点可能红色冲突,再将祖父节点代入继续调整)
            {
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;
                x = x->parent->parent;
                continue;
            }
            else                               //父红叔黑
            {
                if(x == x->parent->right)//如果操作节点x是右子,对父节点左旋(操作后新的x为左子且父红叔黑)
                {
                    x = x->parent;
                    rotateLeft(x);
                }
                //如果操作节点x是左子,将父节点染黑,祖父节点染红后右旋(原x节点升祖父)
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                rotateRight(x->parent->parent);
            }
        }
        else                                    //如果操作节点x的父节点是右子
        {
            Node<T>* y = x->parent->parent->left;//叔节点
            if(y != nullptr && y->color == RED)//父叔都为红色,则将父叔都染黑,将祖父节点染红,继续对祖父节点操作
            {
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;
                x = x->parent->parent;
                continue;
            }
            else                                //父红叔黑
            {
                  if(x == x->parent->left)//如果操作节点x是左子,将操作父节点右旋,把x处理成右子
                  {
                      x = x->parent;
                      rotateRight(x);
                  }
                  //如果操作节点x是右子,将父节点染黑,祖父节点染红后左旋(原x升祖父)
                  x->parent->color = BLACK;
                  x->parent->parent->color = RED;
                  rotateLeft(x->parent->parent);
            }
        }
    }
    root->color = BLACK;
}

插入函数

template<typename T>
void RedBlackTree<T>::insert(const T& val)
{
    if(root == nullptr)//根节点为空,直接插入新根黑色
    {
        root = new Node<T>(val);
        root->color = BLACK;
        return;
    }
    Node<T>* x = root;
    Node<T>* y = nullptr;
    while(x != nullptr)//找到val该插入的叶子节点,y为x父节点,结束循环是x是空
    {
        y = x;
        if(val < x->data)
        {
            x = x->left;
        }
        else if(val > x->data)
        {
            x = x->right;
        }
        else
        {
            return;
        }
    }
    Node<T>* z = new Node<T>(val);
    z->parent = y;
    if( val < y->data)//新节点插入y下方
    {
        y->left = z;
    }
    else if(val > y->data)
    {
        y->right = z;
    }
    insertFix(z);//修复
}

删除修复
相对插入的默认红色,删除时情况稍显复杂。等完善后补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值