码迷,mamicode.com
首页 > 其他好文 > 详细

红黑树

时间:2016-07-15 21:24:51      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

红黑树是一种平衡的二叉排序树,首先它是二叉排序树,即它的节点之间都是有序的; 其次,它是一种平衡树,因此它的查找效率是比较优的

红黑树的五个性质:

1、每个节点要么是红色的要么是黑色的

2、根节点必须是黑色的

3、叶子节点(即NULL节点)是黑色的

4、如果一个节点是红色的,那么它的两个孩子必须是黑色的

5、对于每一个节点,它到叶子节点的所有路径包含的黑色节点的个数都相同


由于性质5的原因,新插入的节点的颜色必须是红色的!

由于性质4的原因,新插入节点可能破坏了红黑树的平衡,因此需要调整

注意每一个节点的初始插入位置都是在树的最底层,插入之后判断是否违反了红黑树的性质,如果违反了,那么需要进行调整


实现:

#ifndef RB_RBTree_H
#define RB_RBTree_H

#include <iostream>
#include <string>

using namespace std;

struct RBTreeNode;

// 树节点数据的比较函数,如果不设置那么就默认按照指针进行比较
typedef int (*RBTreeDataCompareFunc)(void* data1,void* data2);

// 遍历一棵树的处理函数
typedef void (*RBTreeNodeHandle)(void* userData,RBTreeNode* node);


// 红黑树的节点
struct RBTreeNode
{
    enum RBTreeNodeColor
    {
        // 红色
        red,
        // 黑色
        black,
    };

    RBTreeNode()
    {
        data = 0;
        left = 0;
        right = 0;
        parent = 0;
        color = red;
    }

    // 数据
    void* data;
    // 颜色
    int color;
    // 父亲
    struct RBTreeNode* parent;
    // 左孩子
    struct RBTreeNode* left;
    // 右孩子
    struct RBTreeNode* right;

    // 取得以node为根的子树的最小节点
    static RBTreeNode* Mini(RBTreeNode* node)
    {
        if(node == 0)
            return 0;

        while(node->left != 0)
            node =node->left;

        return node;
    }

    // 取得以node为子树的最大节点
    static RBTreeNode* Max(RBTreeNode* node)
    {
        if(node == 0)
            return 0;

        while(node->right != 0)
            node = node->right;

        return node;
    }
};


typedef RBTreeNode* PRBTreeNode;

// 红黑树
class RBTree
{
public:
    RBTree();
    RBTree(RBTreeDataCompareFunc compareFunc);
    ~RBTree();

    RBTreeNode* Root();
    size_t Size();
    bool Empty();
    void Clear();

    // 插入节点
    RBTreeNode* Insert(void* data);

    // 获得最左边的节点
    RBTreeNode* LeftMost();

    // 获得最右边的节点
    RBTreeNode* RightMost();

    // 重新调整平衡
    void ReBalance(RBTreeNode* x);
    // 向左旋转
    void RotateLeft(RBTreeNode* x);
    // 向右旋转
    void RotateRight(RBTreeNode* x);

    // 删除值等于data的节点
    void Remove(void* data);

    // 删除node节点,连同它的子节点
    void Remove(RBTreeNode* node);

    // 删除node节点的左节点(连同它的子节点)
    void RemoveLeft(RBTreeNode* node);
    // 删除node节点的右节点(连同它的子节点)
    void RemoveRight(RBTreeNode* node);

    // 中序递归遍历
    void MidOrderTraverse(RBTreeNodeHandle handle,void* userData,RBTreeNode* node = 0);
    // 前序递归遍历
    void PreOrderTraverse(RBTreeNodeHandle handle,void* userData,RBTreeNode* node = 0);
    // 后续递归遍历
    void PostOrderTraverse(RBTreeNodeHandle handle,void* userData,RBTreeNode* node = 0);

    // 查找
    RBTreeNode* Find(void* data);

    RBTreeNode* Find(void* data,PRBTreeNode& parentNode);

    size_t Depth(RBTreeNode* node = 0);
    size_t Leafs(RBTreeNode* node = 0);
private:
    void ClearRecu(RBTreeNode* node);
    RBTreeNode* FindRecu(RBTreeNode* node,void* data,PRBTreeNode& parentNode);
    // 中序递归遍历
    void MidOrderTraverseRecu(RBTreeNodeHandle handle,void* userData,RBTreeNode* node );
    // 前序递归遍历
    void PreOrderTraverseRecu(RBTreeNodeHandle handle,void* userData,RBTreeNode* node );
    // 后续递归遍历
    void PostOrderTraverseRecu(RBTreeNodeHandle handle,void* userData,RBTreeNode* node );

    size_t DepthRecu(RBTreeNode* node );
    size_t LeafsRecu(RBTreeNode* node );
private:

    // m_pHead的父亲始终指向根节点
    // m_pHead的left指向最左的节点(也就是值最小的节点)
    // m_pHead的right指向最右的节点(也就是值最大的节点)
    RBTreeNode* m_pHead;

    // 红黑树中节点的个数
    size_t m_nSize;

    // 比较函数
    RBTreeDataCompareFunc m_CompareFunc;
};

#endif // RBTree_H

#include "rbtree.h"

// 默认的节点值比较函数
int DefaultRBTreeNodeCompareFunc(void* data1,void* data2)
{
    if(data1 == data2)
        return 0;

    if(data1 < data2)
        return -1;

    return 1;
}

// 构造函数
RBTree::RBTree()
{
    m_pHead = new RBTreeNode;
    m_pHead->color = RBTreeNode::red;
    m_pHead->left = m_pHead;
    m_pHead->right = m_pHead;
    m_pHead->parent = 0;

    m_nSize = 0;

    m_CompareFunc = DefaultRBTreeNodeCompareFunc;
}

RBTree::RBTree(RBTreeDataCompareFunc compareFunc)
{
    m_nSize = 0;

    m_pHead = new RBTreeNode;
    m_pHead->color = RBTreeNode::red;
    m_pHead->left = m_pHead;
    m_pHead->right = m_pHead;
    m_pHead->parent = 0;

    m_CompareFunc = compareFunc;
}

RBTree::~RBTree()
{
    Clear();
    delete m_pHead;
}

// 返回根节点
RBTreeNode* RBTree::Root()
{
    return m_pHead->parent;
}

// 返回红黑树最左边的节点,即最小值所在的节点
RBTreeNode* RBTree::LeftMost()
{
    return m_pHead->left;
}

// 返回红黑树最优边的节点,即最大值所在的节点
RBTreeNode* RBTree::RightMost()
{
    return m_pHead->right;
}

// 返回红黑树的节点个数
size_t RBTree::Size()
{
    return m_nSize;
}

bool RBTree::Empty()
{
    if(0 == m_nSize)
        return true;

    return false;
}

// 清理红黑树
void RBTree::Clear()
{
    ClearRecu(m_pHead->parent);

    m_pHead->color = RBTreeNode::red;
    m_pHead->left = m_pHead;
    m_pHead->right = m_pHead;
    m_pHead->parent = 0;
    m_nSize = 0;
}

// 递归清理
void RBTree::ClearRecu(RBTreeNode *node)
{
    if(node == 0)
        return ;

    ClearRecu(node->left);
    ClearRecu(node->right);
    delete node;
    --m_nSize;
}

// 节点node的值要大于等于左孩子的值
// 插入节点
RBTreeNode* RBTree::Insert(void* data)
{
    // 创建一个新节点
    RBTreeNode* insertNode = new RBTreeNode;
    insertNode->data = data;
    // 新插入节点的颜色是红色的
    insertNode->color = RBTreeNode::red;

    ++m_nSize;

    // 如果根节点为空,那么把当前节点设置为根节点
    // 把颜色调整为黑,因为红黑树的根是黑色的
    if(m_pHead->parent == 0)
    {
        m_pHead->parent = insertNode;
        m_pHead->parent->color = RBTreeNode::black;

        m_pHead->left = insertNode;
        m_pHead->right = insertNode;
    }
    else
    {
        RBTreeNode* node = m_pHead->parent;
        RBTreeNode* currentpNode = node;

        // 找到新节点应该插入的位置
        while(node != 0)
        {
            currentpNode = node;

            int compareRet = m_CompareFunc(node->data,data);

            if(compareRet < 0)
            {
                node = node->right;
            }
            else
            // compareRet >= 0
            {
                node = node->left;
            }
        }

        // 把新节点插入红黑树中
        if(m_CompareFunc(currentpNode->data,data) < 0)
        {
            currentpNode->right = insertNode;
            insertNode->parent = currentpNode;

            if(RightMost() == currentpNode)
                m_pHead->right = insertNode;
        }
        else
        {
            currentpNode->left = insertNode;
            insertNode->parent = currentpNode;

            if(LeftMost() == currentpNode)
                m_pHead->left = insertNode;
        }
    }

    // 插入好了
    // 接下来需要进行调整
    ReBalance(insertNode);
}

// 红黑树的特点:
// (1)根节点是黑色的
// (2)父子节点不能同时是红色(即如果父亲节点是红色,那么子节点必须是黑色)
// (3)任一节点到NULL(即树尾端)的任何路径包含的黑色节点个数都相同

// 假设插入节点是X,X的父亲节点是P,X的祖父是G,X的曾祖父是GG,X的伯父或者叔叔(即P的兄弟)是S
// 有四种情况:
// 1、如果P的颜色是黑色,插入之后可以直接返回
// 2、如果P的颜色是红色,那么进行如下处理
// 2.1、S是黑色:
// 2.1.1、LL:如果X是外侧插入,直接进行LL旋转(对P和G),改变P和G的颜色(P改成黑,G改成红色)
// 2.1.2、LR:如果X是内侧插入,进行LR旋转,先对P、X进行旋转,然后改变G和X的颜色(G改成红色,X改成黑色)
//           再对G进行旋转
// 2.2、S是红色:
// 2.2.1、LL:如果X是外侧插入,直接进行LL旋转(对P和G),改变X的颜色(变成黑色),如果GG是黑色,那么完成
//           否则还需要继续向上处理
//


/*
 * 预处理过程:
 * 从某个节点依次向上,如果遇到某个节点X的两个子节点的颜色都是红色
 * 那么把X两个子节点的颜色改成黑色,X的颜色改成红色,然后继续向上
 * 如果变换之后,X的父亲和X都是红色(那此时X的祖父必是黑色,因为X的父亲是红色),
 * 如果此时X的兄弟是红色,那么可以继续向上处理(因为符合P的两个子节点都是红色这一条件)
 * 如果此时X的兄弟是黑色(那么不满足继续向上的条件了),需要进行旋转
 * 那么对X的父亲进行旋转即可,这里只需要一个LL(或RR)或LR(或RL)旋转即可,而不需要进行多次的向上遍历然后旋转
 * 单旋转的时候需要改变P和G的颜色
 * 双旋转的第一次旋转需要改变X和G的颜色,第二次旋转不需要改变颜色
 */

void RBTree::ReBalance(RBTreeNode *x)
{
    // 插入节点的起始颜色都是红色
    x->color = RBTreeNode::red;

    // 如果P的颜色是黑色,对应情况1,不会进入循环

    // 一直从x向上遍历,直到到达根节点
    while(x != m_pHead->parent && x->parent->color == RBTreeNode::red)
    {
        // P的颜色是红色!!!


        // 如果P是G的左孩子
        if(x->parent == x->parent->parent->left)
        {
            // 取得S
            RBTreeNode* uncle = x->parent->parent->right;

            // S的颜色是红色
            if(uncle && uncle->color == RBTreeNode::red)
            {
                // 这是预处理过程

                // P的颜色设置为黑色
                x->parent->color = RBTreeNode::black;
                // S的颜色设置为黑色
                uncle->color = RBTreeNode::black;
                // G的颜色设置为红色
                x->parent->parent->color = RBTreeNode::red;
                // 然后把X向上移动到G,继续向上遍历,这是一个自下而上的预处理过程
                x = x->parent->parent;
            }
            else
            // S的颜色是黑色
            {
                // 如果X是P的右孩子,而P是G的左孩子,那么将进行LR旋转
                // LR选择即先左旋转,再右旋转
                if(x == x->parent->right)
                {
                    x = x->parent;
                    RotateLeft(x);
                }

                // 如果X是P的左孩子,而P是G的左孩子,那么将进行LL旋转(直接右旋转即可)
                // P的颜色变为黑色
                x->parent->color = RBTreeNode::black;
                // G的颜色变为红色
                x->parent->parent->color = RBTreeNode::red;
                // 进行旋转
                RotateRight(x->parent->parent);
            }
        }
        else
        // 如果P是G的右孩子
        {
            RBTreeNode* uncle = x->parent->parent->left;

            // S的颜色是红色
            if(uncle && uncle->color == RBTreeNode::red)
            {
                // 这是预处理过程


                // P的颜色设置为黑色
                x->parent->color = RBTreeNode::black;
                // S的颜色设置为黑色
                uncle->color = RBTreeNode::black;
                // G的颜色设置为红色
                x->parent->parent->color = RBTreeNode::red;
                // 把X移动到G,依次向上处理,这是一个子下而上的预处理过程
                x = x->parent->parent;
            }
            else
            // S的颜色是黑色
            {
                // 如果X是P的左孩子,而P是G的右孩子,那么需要进行RL旋转(先右旋转,再左旋转)
                if(x == x->parent->left)
                {
                    x =x->parent;
                    RotateRight(x);
                }
                // 如果X是P的右孩子,那么直接进行RR旋转即可(即进行左旋转)
                // P的颜色改成黑色
                x->parent->color = RBTreeNode::black;
                // G的颜色改成红色
                x->parent->parent->color = RBTreeNode::red;
                // 旋转
                RotateLeft(x->parent->parent);
            }
        }
    }

    m_pHead->parent->color = RBTreeNode::black;
}

// 左旋转(以X为中间进行逆时针旋转)
// 旋转之后,X的右孩子right取代X的位置,而X则成为right的左孩子
// 因此right的左孩子应该成为X的右孩子
void RBTree::RotateLeft(RBTreeNode *x)
{
    // 取得x的左孩子
    RBTreeNode* right = x->right;

    // x的右孩子应该是right的左孩子
    x->right =right->left;

    if(right->left != 0)
    {
        // right的左孩子的父亲是x
        right->left->parent = x;
    }

    // right的父亲是x原来的父亲
    right->parent = x->parent;

    if(x == m_pHead->parent)
    {
        m_pHead->parent = right;
    }
    else if(x == x->parent->left)
    {
        x->parent->left = right;
    }
    else
    {
        x->parent->right = right;
    }

    // x变成right的左孩子
    right->left = x;
    x->parent = right;
}

// 右旋转(以X为中心,按照顺时针进行旋转)
// 旋转之后X的左孩子left取代X的位置,X成为left的右孩子
// left原来的右孩子变成X的左孩子
void RBTree::RotateRight(RBTreeNode *x)
{
    RBTreeNode* left = x->left;
    x->left =left->right;

    if(left->right != 0)
    {
        left->right->parent = x;
    }

    left->parent = x->parent;

    if(x == m_pHead->parent)
    {
        m_pHead->parent = left;
    }
    else if(x == x->parent->right)
    {
        x->parent->right = left;
    }
    else
    {
        x->parent->left = left;
    }

    left->right = x;
    x->parent = left;
}


RBTreeNode* RBTree::Find(void *data)
{
    PRBTreeNode node = 0;
    return FindRecu(m_pHead->parent,data,node);
}

RBTreeNode* RBTree::Find(void *data, PRBTreeNode &parentNode)
{
    parentNode = 0;
    return FindRecu(m_pHead->parent,data,parentNode);
}

RBTreeNode* RBTree::FindRecu(RBTreeNode *node, void *data,PRBTreeNode& parentNode)
{
    if(node == 0)
    {
        parentNode = 0;
        return 0;
    }

    if(m_CompareFunc(node->data,data) == 0)
        return node;

    parentNode = node;

    RBTreeNode* temp = FindRecu(node->left,data,parentNode);



    if(0 != temp)
        return temp;

    parentNode = node;

    return FindRecu(node->right,data,parentNode);
}


void RBTree::PreOrderTraverse(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
    if(node == 0)
        return PreOrderTraverseRecu(handle,userData,m_pHead->parent);
    return PreOrderTraverseRecu(handle,userData,node);
}

void RBTree::MidOrderTraverse(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
    if(node == 0)
        return MidOrderTraverseRecu(handle,userData,m_pHead->parent);
    return MidOrderTraverseRecu(handle,userData,node);
}

void RBTree::PostOrderTraverse(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
    if(node == 0)
        return PostOrderTraverseRecu(handle,userData,m_pHead->parent);
    return PostOrderTraverseRecu(handle,userData,node);
}

void RBTree::PreOrderTraverseRecu(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
    if(node == 0)
        return ;
    handle(userData,node);
    PreOrderTraverseRecu(handle,userData,node->left);
    PreOrderTraverseRecu(handle,userData,node->right);

}

void RBTree::MidOrderTraverseRecu(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
    if(node == 0)
        return ;

    MidOrderTraverseRecu(handle,userData,node->left);
    handle(userData,node);
    MidOrderTraverseRecu(handle,userData,node->right);

}

void RBTree::PostOrderTraverseRecu(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
    if(node == 0)
        return ;

    PostOrderTraverseRecu(handle,userData,node->left);
    PostOrderTraverseRecu(handle,userData,node->right);
    handle(userData,node);
}

size_t RBTree::Depth(RBTreeNode *node)
{
    if(node == 0)
        return DepthRecu(m_pHead->parent);
    else
        return DepthRecu(node);
}

size_t RBTree::DepthRecu(RBTreeNode *node)
{
    if(node == 0)
        return 0;

    if(node->left == 0 && node->right == 0)
        return 1;

    int leftDepth = DepthRecu(node->left);
    int rightDepth = DepthRecu(node->right);

    if(leftDepth > rightDepth)
        return leftDepth + 1;
    else
        return rightDepth + 1;

}

size_t RBTree::Leafs(RBTreeNode *node)
{
    if(node == 0)
        return LeafsRecu(m_pHead->parent);
    else
        return LeafsRecu(node);
}

size_t RBTree::LeafsRecu(RBTreeNode *node)
{
    if(node == 0)
        return 0;

    if(node->left == 0 && node->right == 0)
        return 1;
    else
        return LeafsRecu(node->left) + LeafsRecu(node->right);
}


红黑树

标签:

原文地址:http://blog.csdn.net/nb_vol_1/article/details/51915328

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!