数据结构拾遗(2) --红黑树的设计与实现(中)

简介: Insert完善    根据规则4, 新增节点必须为红; 根据规则3, 新增节点之父节点必须为黑.

Insert完善

    根据规则4, 新增节点必须为红; 根据规则3, 新增节点之父节点必须为黑.

 

示例:

    (1)插入16(红色)/55(红色), 则既不用旋转, 也不用重新染色

    (2)插入82(红色), 则违反了红黑规则, 需要进行动态的调整;

 

红黑树所需的处理

1.单旋转


     新插入的X与其父P都是红色的, 而且X还是G的外部孙子;

 

2.双旋转


    新插入的X与其父P都是红色的, 而且X还是G的内部孙子;

 

3.还需要处理有两个红色孩子的节点, 将右儿子变成黑色的, 我们只允许左儿子是红色的;方法: 旋转+重新染色

 

insert完整实现代码:

/**注意带有 ++ 注释的为新添加的代码**/
template <typename Comparable>
void RedBlackTree<Comparable>::insert(const Comparable &x)
{
    current = parent = grand = great = header;
    nullNode->element = x;

    while (current->element != x)
    {
        //让祖父成为曾祖父, 父亲成为祖父, 自己成为父亲
        //每个人都长了一辈
        great = grand;
        grand = parent;
        parent = current;

        current = (x < current->element) ? current->left
                  : current->right;

        // ++
        //+ 处理1. 如果current节点有两个红孩子
        if ((current->left->color == RED) && (current->right->color == RED))
            handleReorient( x );
    }

    //如果树中包含相同的元素
    if (current != nullNode)
        throw DuplicateItemException();

    current = new Node(x, nullNode, nullNode);
    if (x < parent->element)
        parent->left = current;
    else
        parent->right = current;

    // ++
    //+ 处理2. 如果新插入的节点破坏了红黑规则, 则还需做一次处理
    handleReorient( x );
}
/**自动平衡函数:
    [1]重新染色
    [2]自动旋转
*/
template <typename Comparable>
void RedBlackTree<Comparable>::handleReorient(const Comparable & item)
{
    // 将current节点染成红色
    current->color = RED;
    // 将current的left和right节点染成黑色
    current->left->color = current->right->color = BLACK;

    // 如果current节点的父节点也是红的 -> 单旋转 or 双旋转
    if( parent->color == RED )
    {
        //则将其祖父(爷爷)的颜色染成红色
        grand->color = RED;

        //然后判断新插入的节点是否是内部孙子?
        //如果是, 则增加一次旋转->构成双旋转

        //if注释: 如果该节点小于爷爷, 小于爸爸, 这两种情况不同时满足
        //则说明其是爷爷的内孙子
        if( (item < grand->element) != (item < parent->element) )
        {
            // 则依grand(祖父)节点进行旋转
            parent = rotate( item, grand );  // Start double rotate
        }
        // 则依great(曾祖父)节点进行旋转
        current = rotate( item, great );

        //令当前节点为黑色
        current->color = BLACK;
    }

    //根节点必须是黑色的
    header->right->color = BLACK; // Make root black
}
// 自动判断并进行旋转函数
template <typename Comparable>
typename RedBlackTree<Comparable>::Node *
RedBlackTree<Comparable>::rotate(const Comparable &item,
                                 Node *theParent )
{
    //位于theParent的左子树
    if( item < theParent->element )
    {
        //如果为真, 则说明theParent->left有左孩子,
        //否则, 有右孩子
        item < theParent->left->element ?
        //如果theParent左边有一棵子树, 则以theParent->left
        //为轴, 向右转
        rotateWithLeftChild( theParent->left )  :  // LL
        //如果theParent右边有一棵子树, 则以theParent->left
        //为轴, 向左转
        rotateWithRightChild( theParent->left ) ;  // LR

        return theParent->left;     //返回左子树
    }
    else    //位于右子树
    {
        //如果为真, 则说明theParent->right有左孩子,往右转
        //否则, 有右孩子, 往左转
        item < theParent->right->element ?
        rotateWithLeftChild( theParent->right ) :  // RL
        rotateWithRightChild( theParent->right );  // RR

        return theParent->right;    //返回右子树
    }
}

测试代码:

int main()
{
    //用NEG_INF来代表负无穷大
    const int NEG_INF = -999999;
    RedBlackTree<int> tree(NEG_INF);

    tree.insert(50);
    cout << tree.header->right->element << " " << tree.header->right->nodeColor() << endl;
    cout << endl;
    tree.insert(40);
    cout << tree.header->right->left->element << " " << tree.header->right->left->nodeColor() << endl << endl;

    //此时需要进行旋转和重新染色
    tree.insert(30);
    cout << tree.header->right->element << " " << tree.header->right->nodeColor() << endl ;
    cout << tree.header->right->left->element << " " << tree.header->right->left->nodeColor() << endl;
    cout << tree.header->right->right->element << " " << tree.header->right->right->nodeColor() << endl;

    return 0;
}

//由于需要用到nodeColor成员函数, 因此我们将RedBlackNode类改造如下:
template <typename Comparable>
class RedBlackNode
{
    friend class RedBlackTree<Comparable>;
public:
    RedBlackNode(const Comparable &theElement = Comparable(),
                 RedBlackNode *theLeft = NULL,
                 RedBlackNode *theRight = NULL,
                 int theColor = RedBlackTree<Comparable>::BLACK)
        : element(theElement), left(theLeft), right(theRight), color(theColor) {}

public:
    //返回当前节点的颜色, 以作测试
    std::string nodeColor() const
    {
        return (color == RedBlackTree<Comparable>::BLACK) ? "black" : "red";
    }

public:
    Comparable element;
    RedBlackNode *left;
    RedBlackNode *right;
    int color;
};

红黑树其他操作

template <typename Comparable>
class RedBlackTree
{
    ...
    bool isEmpty() const;
    void makeEmpty();

    Gref<Comparable> find(const Comparable & x) const;
    Gref<Comparable> findMin() const;
    Gref<Comparable> findMax() const;

    //递归删除所有节点
    void reclainMemory(Node *t) const;
    ...
};


//析构函数完善版本
template <typename Comparable>
RedBlackTree<Comparable>::~RedBlackTree()
{
    if (!isEmpty())
        makeEmpty();

    delete nullNode;
    delete header;
}

//红黑树查找:与二叉查找树类似
template <typename Comparable>
Gref<Comparable> RedBlackTree<Comparable>::find(const Comparable &x) const
{
    if (isEmpty())
        return Gref<Comparable>();

    nullNode->element = x;
    Node *iter = header->right;

    while (true)
    {
        if (x < iter->element)
            iter = iter->left;
        else if (x > iter->element)
            iter = iter->right;

        //如果 x == iter->element
        else if (iter != nullNode)
            return Gref<Comparable>(iter->element) ;
        else
            return Gref<Comparable>();
    }
}

//查找最大值: 一路向右
template <typename Comparable>
Gref<Comparable> RedBlackTree<Comparable>::findMax() const
{
    if (isEmpty())
        return Gref<Comparable>();

    Node *iter = header->right;
    while (iter->right != nullNode)
    {
        // 一直向右走
        iter = iter->right;
    }

    return Gref<Comparable>(iter->element);
}

//查找最小值: 一路向左
template <typename Comparable>
Gref<Comparable> RedBlackTree<Comparable>::findMin() const
{
    if (isEmpty())
        return Gref<Comparable>();

    Node *iter = header->right;
    while (iter->left != nullNode)
    {
        // 一直向左走
        iter = iter->left;
    }

    return Gref<Comparable>(iter->element);
}

template <typename Comparable>
bool RedBlackTree<Comparable>::isEmpty() const
{
    if (header->right == nullNode)
        return true;
    return false;
}

template <typename Comparable>
void RedBlackTree<Comparable>::makeEmpty()
{
    reclainMemory(header->right);
    header->right = nullNode;
}

template <typename Comparable>
void RedBlackTree<Comparable>::reclainMemory(Node *t) const
{
    //t == t->left的时候, 是当t==nullNode时
    if (t != t->left)
    {
        reclainMemory(t->left);
        reclainMemory(t->right);
        delete t;
    }
}

Gref设计与实现

//一个包装器: 将指针封装成为引用
template <typename Object>
class Gref
{
public:
    Gref(): obj(NULL) {}
    explicit Gref(const Object &x)
        : obj(& x) {}

    const Object &get() const
    {
        if (isNull())
            throw NullPointerException();
        else
            return * obj;
    }

    bool isNull() const
    {
        if (obj == NULL)
            return true;
        return false;
    }

private:
    const Object * obj;
};

目录
相关文章
|
4月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
112 1
【数据结构】红黑树——领略天才的想法
【数据结构】红黑树——领略天才的想法
|
2月前
|
Java C++
【数据结构】探索红黑树的奥秘:自平衡原理图解及与二叉查找树的比较
本文深入解析红黑树的自平衡原理,介绍其五大原则,并通过图解和代码示例展示其内部机制。同时,对比红黑树与二叉查找树的性能差异,帮助读者更好地理解这两种数据结构的特点和应用场景。
38 0
|
7月前
【数据结构】红黑树的原理及其实现
【数据结构】红黑树的原理及其实现
|
4月前
|
存储 Java 程序员
"揭秘HashMap底层实现:从数组到链表,再到红黑树,掌握高效数据结构的秘密武器!"
【8月更文挑战第21天】HashMap是Java中重要的数据结构,采用数组+链表/红黑树实现,确保高效查询与更新。构造方法初始化数组,默认容量16,负载因子0.75触发扩容。`put`操作通过计算`hashCode`定位元素,利用链表或红黑树处理冲突。`get`和`remove`操作类似地定位并返回或移除元素。JDK 1.8优化了链表转红黑树机制,提升性能。理解这些原理能帮助我们更高效地应用HashMap。
50 0
|
6月前
|
算法 架构师 NoSQL
【数据结构之红黑树】深入原理与实现
意节点的左子树和右子树的层高差不大于1,为了维护树的平衡,我们介绍了树的左右旋转。但是,AVL树维护平衡的代价是比较大的。所以,我们又介绍了红黑树这种数据结构,这是因为红黑树插入的效率相对AVL树是比较高的,在统计意义上来讲红黑树在插入和查找综合上效率是比较高的,这也是为什么红黑树为什么广泛应用在计算机各个方面。
62 2
|
6月前
|
C++
数据结构===红黑树
数据结构===红黑树
|
7月前
|
存储 算法 Java
数据结构/C++:红黑树
数据结构/C++:红黑树
43 3
|
7月前
数据结构===红黑树
红黑树是平衡二叉搜索树,关键点在于其满足5个性质,包括根节点为黑,叶子为黑,红色节点不能相邻且路径上黑节点数相等。插入和删除时结合左旋、右旋操作。插入时,针对叔叔节点颜色(红或黑),参照AVL树的失衡处理,分为4种情况,并调整颜色策略。删除操作同样复杂,涉及节点替换和颜色调整。
49 1
|
7月前
|
存储 缓存 算法
数据结构与算法 树(B树,B+树,红黑树待完善)
数据结构与算法 树(B树,B+树,红黑树待完善)
64 0