C++【红黑树】

目录

一、什么是红黑树

红黑树的性质

情况一:cur为红,p为红,g为黑,u存在且为红

 case1:a/b/c/d/e是空树,cur是新增

case2:a/b/c/d/e不为空,cur是新增

 情况二:cur为红,p为红,g为黑,u不存在,或者u存在但是为黑色

case1:u不存在,cur是新增,a/b/c/d/e都是空树

case2:u存在且为黑

情况三:cur为红,p为红,g为黑,u不存在或者u存在且为黑色

case1:u不存在,cur就是新增的节点

case2:u存在且为黑

代码实现

检测代码

二、封装红黑树

写在set.h中的内容

写在map.h当中的内容

三、红黑树的迭代器

1.前置++

2.前置--

3.后置++和--

4.比较运算符的重载

5.*和->的重载

四、代码的汇总

1.RBTree.h

2.Map.h

3.set.h

4.main.cpp


一、什么是红黑树

AVLTree:要求左右高度差不超过1

红黑树:AVLTree过分严格,可能会导致过分的旋转,那能不能不要那么严格呢?

需要达到的目的,最长路径不超过最短路径的二倍。

也就是说,我们的AVLTree是严格平衡,我们的红黑树是不严格平衡,而是近似平衡

结果:相对而言,插入同样的数据,AVL树的旋转更多,红黑树的旋转次数更少

 假设N是100w,AVL树为logN的高度,也就是大概20左右

但是我们的红黑树的话,最短的高度大概是logN也就是20左右,最深的应该为2*logN,为40次左右。

红黑树的性质

1.每个结点不是红色,就是黑色

2.根节点是黑色的

3.如果一个节点是红色的,则它的两个孩子结点是黑色的(解读:树中没有连续的红色结点)

4.对于每个节点,从给结点到其所有的后代叶结点的简单路径上,均包含相同数目的黑色结点(解读:每条路径上的黑色结点的数量相等)

5.每个叶子结点都是黑色的(这里的叶子结点指的是空节点) 

 上面的图中一共有几条路径?

(从根节点到空节点才算一条路径)

一共有11条

 每个叶子结点都是黑色的(这里的叶子结点指的是空节点

这里的叶子结点又称为NIL结点

为什么?

假设只有两个结点

 那么我们这里假设的是叶子结点(不是空节点)是黑色的,那么我们并不能做到每条路径上的黑色结点的数量是相等的。我们这里的叶子结点必须是红色的。

为什么这几条规则就能够保证最长的路径中的结点个数不超过最短路径的结点个数的两倍?

每条路径都有相同数量的黑的结点

那么极限的最短一定是全黑的路径。

那么极限的最长路径一定是在每个黑色结点之间插入一个红色的结点,也就是一黑一红排布的结点。

如果你把黑色的结点全部都拿出来,那么我们可以认为我们的树基本是一棵满二叉树了。 

新插入结点,插入什么颜色?

红色:规则三(如果一个节点是红色的,则它的两个孩子结点是黑色的(解读:树中没有连续的红色结点))

黑色:规则四 (对于每个节点,从给结点到其所有的后代叶结点的简单路径上,均包含相同数目的黑色结点(解读:每条路径上的黑色结点的数量相等))

明显插入红色的更加方便

我们这里插入结点需要变色+旋转

因为控制住了颜色,那么我们就能够将我们的高度给控制住 

这里我们先初步理解一下红黑树的调整方案 

  

 我们这里不妨假设在27的右子树的地方插入新节点,并且插入的新结点是红色的,为了满足我们的规则三,我们必须将我们的27结点设置成黑色的。因为不能有两个连续的红色结点。如果我们新插入的节点是黑色的话,就不满足我们上面新插入的结点是红色的原则了。

遇事不决看叔叔。

如果叔叔存在,也为红,那如果parent变黑了,那么叔叔和parent一起背锅,也变成黑色的 

 

为什么叔叔也要变成黑色的呢?

因为我们的parent的这条路径上多了一个黑色的结点,那么我们需要遵循我们的第四条规则,给我们uncle的这条结点也增加一个黑色结点.,所以我们将uncle结点也变成黑色的。

这里的祖父一定是黑色的,因为插入之前,我们的红黑树一定是满足规则的,所以我们的父亲是红色的话,我们的祖父节点一定是黑色的。

然后还是遵循第四条规则,每条路径上的黑色的结点的数目是一样的,所以我们需要将祖父结点的颜色从黑色变成红色的

 这样我们的黑色结点的数量就不会发生变化。

但是我们这里的17和25都是红色的,我们还需要继续向上调整 。

这一轮循环和我们上面这一轮调整是一样的,也就是cur的parent和cur都是红色的,然后我们需要将parent编程黑色的,同时将uncle也变成黑色的,然后将grandparent变成红色的 

 这里我们的cur再次指向grandparent的位置,然后我们发现我们此时的cur已经是根节点了,那么我们就停止调整了。

此时我们观察到其实我们每一条路径上都多了一个黑色的结点。 

我们发现这里的红黑树插入了这个新的节点之后,其实左右高度差已经超过了1,但是我们并没有进行旋转。

仅仅是变色,我们就让我们的红黑树再次满足了条件。  

但是上述的情况是叔叔结点存在且为红的情况,要是我们的叔叔结点为黑色呢? 

那我们这个时候就不能仅仅是变色了。

我们此时的最长路径是5,最短路径是2,是右边高,左边第要是和我们刚刚一样,将parent和uncle都变成黑色的,那么我们的右边的parent所在的所有分支都会比我们左边的子树都多一个黑色的结点,那么我们就没办法仅仅是通过变色来调平衡了

我们需要像上面的旋转一样,将我们的15结点挂载到我们13的右节点,然后再将我们的13的这个结点变成红色的结点。从而满足我们红黑树的条件。

情况一:cur为红,p为红,g为黑,u存在且为红

cur是当前位置的结点

p是parent结点

g是grandfather结点

u是uncle结点

下面的是抽象图,代表着任意多种情况

a/b/c/d/e是我们符合红黑树规则的子树(子树根不一定为黑色的) 

 case1:a/b/c/d/e是空树,cur是新增

p和u变黑,g变红。

p,u变红是为了保证g下面的两颗子树的黑色结点个数相同

g变红是为了让我们的g这一条分支和我们的其他的分支的黑色的数目相同。因为我们的上一步操作,u和p变黑都让我们的这两条分支的黑色的结点个数都加了1,呢么g变红,恰好能让这两条路径的黑色结点-1

继续把g当成cur结点,向上继续迭代处理 

case2:a/b/c/d/e不为空,cur是新增

c/d/e应该是右边四种情况中的一种

cde的组合是4×4×4,插入的结点在ab的左子树和右子树,也是4种情况,所以256种情况,画不完。 

新增的结点可以在a,b的任意孩子位置。

 新插入的结点是红色的,将父亲和叔叔结点变黑,然后将祖父结点变成红色的。

如果g结点已经是根节点了,那么我们就将其变成黑色的 

所以上面两种的case的调整方案其实都是一样的。

都是变色

 情况二:cur为红,p为红,g为黑,u不存在,或者u存在但是为黑色

case1:u不存在,cur是新增,a/b/c/d/e都是空树

在p位置发生右旋,p变成黑色的,祖父变成红色的。

case2:u存在且为黑

新增结点可以在ab孩子的任意位置,de可以是空树或者是一个红结点,c可以是根是黑结点的子树,是下面四种情况中的任意一种

 

c的情况有4中,插入的位置可以是ab的任意子树,有4中,de一共有2×2种情况

所以是4×4×4种情况64

 叔叔存在且为黑,我们就在p的位置进行右旋,p变成根节点的位置,g变到p的右节点,然后p原先的右节点变成g的左子树,然后p变成黑色的,g变成红色的

所以上面两种的case的调整方案其实都是一样的。

都是单旋+变色

情况三:cur为红,p为红,g为黑,u不存在或者u存在且为黑色

这里按照我们上面的推测,我们不妨猜出我们的情况三是双旋+变色

p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反, p为g的右孩子,cur为p的左孩子,则针对p做右单旋转 则转换成了情况2 

case1:u不存在,cur就是新增的节点

 

case2:u存在且为黑

 新增的结点可以在bc的任意孩子位置,a为黑色,de为空树或者是红结点

a可以是下面四种的任意一种

a有四种,新增的结点可以在bc的任意孩子位置,有4中,然后de分别可以为空树或者是红结点,有4种情况,一共是4×4×4,为64种

也就是现在p点左单旋,然后再在g位置进行右单旋

将cur的左,变成p的右,cur变成g的左,然后cur的左节点变成p这个时候就变成情况2了

然后将cur转到根的位置,cur的右子树变成g的左子树,cur的右链接g

然后cur变成黑色的,g变成红色的 

红黑树的关键是看叔叔

如果叔叔存在且为红,变色,继续往上处理 

如果叔叔不存在或者存在且为黑,旋转+变色(单旋还是双旋,左单旋还是右单旋)

代码实现

//插入和我们的avl树其实是差不多的
    bool Insert(const pair<K, V>& kv)
    {
        if (_root == nullptr)
        {
            _root = new Node(kv);
            //根节点必须是黑色的
            _root->_col = BLACK;
            return true;
        }

        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_kv.first < kv.first)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_kv.first > kv.first)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }
        }

        cur = new Node(kv);
        //新插入的接地那默认是红色的
        cur->_col=RED;
        if (parent->_kv.first < kv.first)
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }

        cur->_parent = parent;

        //如果存在parent并且parent的节点的颜色为红色,按照我们不能有两个红色结点连在一起的原则,我们需要进行调整
        while(parent &&parent->_col==RED)
        {
            Node* grandfather=parent->_parent;
            assert(grandfather);
            //父亲是红色的话,祖父结点一定是黑色的,不然我们的红黑树在我们的本次调整之前就已经不满足红黑树的条件了
            assert(grandfather->_col==BLACK);
            // 关键看叔叔
            //父亲是祖父的左
            if (parent == grandfather->_left)
            {
                Node* uncle = grandfather->_right;
                // 情况一 : uncle存在且为红,变色+继续往上处理
                if (uncle && uncle->_col == RED)
                {
                    //父亲和叔叔全部都变成黑色的,把祖父变成红色的
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    // 继续往上处理,将祖父当成cur结点,然后再将cur的父亲找到
                    cur = grandfather;
                    parent = cur->_parent;
                }
                // 情况二+三:uncle不存在 + 存在且为黑
                //看是单旋还是双旋
                else
                {
                    // 情况二:右单旋+变色
                    //     g
                    //   p   u
                    // c
                    //cur是父节点的左子树,左边高,右单旋+变色
                    if (cur == parent->_left)
                    {
                        //对祖父的位置进行右旋
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else
                    {
                        // 情况三:左右单旋+变色
                        //     g
                        //   p   u
                        //     c
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }

                    break;
                }
            }
            //父亲是祖父的右结点
            else // (parent == grandfather->_right)
            {
                Node* uncle = grandfather->_left;
                // 情况一
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    // 继续往上处理
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else
                {
                    // 情况二:左单旋+变色
                    //     g
                    //   u   p
                    //         c
                    if (cur == parent->_right)
                    {
                        RotateL(grandfather);
                        //父亲的颜色变黑,祖父的颜色变红
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else
                    {
                        // 情况三:右左单旋+变色
                        //     g
                        //   u   p
                        //     c
                        //先以parent的位置进行右单旋,然后再祖父结点进行左单旋
                        RotateR(parent);
                        RotateL(grandfather);
                        //cur变黑,祖父变红
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }

                    break;
                }
            }
            //永远将根节点设置为黑色
        _root->_col = BLACK;
        return true;
        }

    }

void _InOrder(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }

        _InOrder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _InOrder(root->_right);
    }

检测代码

我们可以看颜色,或者看高度

但是高度差不超过2倍不一定是红黑树,只有颜色符号我们的四个规则,才是我们的红黑树。

bool IsBalance()
    {
        //空树可以认为是红黑树
        if (_root == nullptr)
        {
            return true;
        }

        //根节点的颜色一定要是黑色
        if (_root->_col == RED)
        {
            cout << "根节点不是黑色" << endl;
            return false;
        }

        // 黑色节点数量基准值

        int benchmark = 0;

        return PrevCheck(_root, 0, benchmark);
    }

//在递归中,blackNum记录根节点--大年结点路径上的黑色结点的数量
    //前序递归遍历即可,深度优先遍历,遍历到根节点,返回这一条路径的所有的黑色结点统计出来的数量
    bool PrevCheck(Node* root, int blackNum, int& benchmark)
    {
        if (root == nullptr)
        {
            //cout << blackNum << endl;
            //return;

            //根节点一定是黑色的,只要我们走完第一条路径,将其benchmark更新成第一条路径的黑色结点的个数
            //然后再看其他路径的benchmark也就是黑色结点的数量是不是和我们第一条的路径的黑色节点的数目一样。
            if (benchmark == 0)
            {
                //记录黑色结点的数量
                benchmark = blackNum;
                return true;
            }

            if (blackNum != benchmark)
            {
                cout << "某条黑色节点的数量不相等" << endl;
                return false;
            }
            else
            {
                //如果是相等的话,就return true返回给上一层
                return true;
            }
        }
        //如果是黑色,记录黑色的数量+1
        if (root->_col == BLACK)
        {
            ++blackNum;
        }

        //不检查孩子,遇到红结点去检查父亲结点的颜色
        if (root->_col == RED && root->_parent->_col == RED)
        {
            cout << "存在连续的红色节点" << endl;
            return false;
        }
        
        //递归遍历当前结点的左子树和右子树
        return PrevCheck(root->_left, blackNum, benchmark)
               && PrevCheck(root->_right, blackNum, benchmark);
    }

    void _InOrder(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }

        _InOrder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _InOrder(root->_right);
    }

void TestRBTree1()
{
    int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, 0,5,30,25,20,4,13,30,28,27};  // 测试双旋平衡因子调节
    //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    RBTree<int, int> t1;
    for (auto e : a)
    {
        t1.Insert(make_pair(e, e));
    }

    t1.InOrder();
    cout << "IsBalance:" << t1.IsBalance() << endl;
}

 随机数据测试代码

void TestRBTree2()
{
    size_t N = 1000;
    srand(time(0));
    RBTree<int, int> t1;
    for (size_t i = 0; i < N; ++i)
    {
        int x = rand();
        cout << "Insert:" << x << ":" << i << endl;
        t1.Insert(make_pair(x, i));
    }
    cout << "IsBalance:" << t1.IsBalance() << endl;
}

 

二、封装红黑树

我们看一下STL底层是怎么将红黑树封装成map和set的

如果是set的话,我们的key_type和value_type其实都是key

如果是map的话,我们的key_type是key,而我们的value_type是pair<const key,T>

也就是说,我们可以用一棵泛型结构的红黑树,通过不同的实例化参数,实现我们的set和map, 

这样就实现了代码复用。

这和我们之前的普通迭代器和const迭代器,正向迭代器和反向迭代器的时候是一样的。 

写在set.h中的内容


#ifndef RBTREE_SET_H
#define RBTREE_SET_H
#include "RBTree.h"
namespace zhuyuan
{
    template<class K>
    class set
    {
        struct SetKeyOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };
    public:
        typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
        typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

        iterator begin()
        {
            return _t.Begin();
        }

        iterator end()
        {
            return _t.End();
        }

        pair<iterator, bool> insert(const K& key)
        {
            //pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
            auto ret = _t.Insert(key);
            return pair<iterator, bool>(iterator(ret.first._node), ret.second);
        }

        iterator find(const K& key)
        {
            return _t.Find(key);
        }
    private:
        RBTree<K, K, SetKeyOfT> _t;
    };

    
}
#endif //RBTREE_SET_H

写在map.h当中的内容

#ifndef RBTREE_MAP_H
#define RBTREE_MAP_H
#include "RBTree.h"
namespace zhuyuan
{
    template<class K, class V>
    class map
    {
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
    public:
        typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
        typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;

        iterator begin()
        {
            return _t.Begin();
        }

        iterator end()
        {
            return _t.End();
        }

        pair<iterator, bool> insert(const pair<K, V>& kv)
        {
            return _t.Insert(kv);
        }

        iterator find(const K& key)
        {
            return _t.Find(key);
        }

        V& operator[](const K& key)
        {
            pair<iterator, bool> ret = insert(make_pair(key, V()));
            return ret.first->second;
        }

    private:
        RBTree<K, pair<K, V>, MapKeyOfT> _t;
    };

}
#endif //RBTREE_MAP_H

三、红黑树的迭代器

1.前置++

中序:左子树 根 右子树

1、右子树不为空,++就是找右子树中序第一个(最左节点)

2、右子树为空,我当前这棵树访问完了,++找孩子不是父亲右的那个祖先

7是6的右孩子,7结束之后找到6,6不是8的右子树,所以访问8

3、父亲是空,也就是找到了根节点的位置,根节点是没有父节点的,所以停止搜索。

(如果有哨兵位的头结点的话,就走到哨兵位的头结点)

//前置++
    Self& operator++()
    {
        if(_node->_right)
        {
            //下一个就是右子树的最左节点
            Node *left=_node->_right;
            while(left->_left)
            {
                left=left->_left;
            }
            _node=left;
            
        }
        else
        {
            //如果右为空
            //找祖先里面孩子不是祖先的右的那一个
            Node* parent=_node->_parent;
            Node* cur=_node;
            //如果是父亲的右子树,就一直往上走
            //如果parent已经为空,那么就停止循环,parent已经到达了我们的end的位置
            while(parent&&cur==parent->_right)
            {
                cur=cur->_parent;
                parent=parent->_parent;
            }
            
            _node=parent;
        }
        return *this;
    }

 2.前置--

1、当前结点的左子树不为空,访问左子树的最右结点

2、孩子是父亲的右的时候,访问父亲,孩子是父亲的左的时候,返回到上一层,再次判断

//前置--
    Self& operator--()
    {

        if(_node->_left)
        {
            //下一个是左子树的最右节点
            Node* right=_node->_left;
            while(right->_right)
            {
                right=right->_right;
            }
            _node=right;
        }
        else
        {
            //孩子不是父亲的左的那个祖先
            Node* parent=_node->_parent;
            Node* cur=_node;
            //如果是父亲的右子树,就一直往上走
            //如果parent已经为空,那么就停止循环,parent已经到达了我们的end的位置
            while(parent&&cur==parent->_left)
            {
                cur=cur->_parent;
                parent=parent->_parent;
            }

            _node=parent;
        }
        return *this;
    }

3.后置++和--

 Self operator--(int)
    {
        Self tmp(*this);

        --(*this);

        return tmp;
    }

 Self operator++(int)
    {
        Self tmp(*this);

        ++(*this);

        return tmp;
    }

4.比较运算符的重载

    bool operator!=(const Self& s) const
    {
        return _node !=s._node;
    }

    bool operator==(const Self& s) const
    {
        return _node ==s._node;
    }

5.*和->的重载

Ref operator*()
    {
        return _node->_data;
    }
    Ptr operator->()
    {
        return &_node->_data;
    }

四、代码的汇总

1.RBTree.h

#ifndef RBTREE_RBTREE_H
#define RBTREE_RBTREE_H
#pragma once

enum Colour
{
    //枚举红色和黑色
    RED,
    BLACK
};

template<class T>
struct RBTreeNode
{
    //和avl树一样都是三叉链
    RBTreeNode<T>* _right;
    RBTreeNode<T>* _left;
    RBTreeNode<T>* _parent;

    //pair<K, V> _kv;
    T _data;//数据
    Colour _col;

    RBTreeNode(const T&data)
            :_left(nullptr)
            , _right(nullptr)
            , _parent(nullptr)
            , _data(data)
    {}
};

template<class T,class Ref,class Ptr>
struct __RBTreeIterator
{
    typedef RBTreeNode<T> Node;
    typedef __RBTreeIterator<T,Ref,Ptr> Self;
    Node * _node;

    __RBTreeIterator(Node* node)
        :_node(node)
    {}

    Ref operator*()
    {
        return _node->_data;
    }
    Ptr operator->()
    {
        return &_node->_data;
    }

    bool operator!=(const Self& s) const
    {
        return _node !=s._node;
    }

    bool operator==(const Self& s) const
    {
        return _node ==s._node;
    }

    //前置++
    Self& operator++()
    {
        if(_node->_right)
        {
            //下一个就是右子树的最左节点
            Node *left=_node->_right;
            while(left->_left)
            {
                left=left->_left;
            }
            _node=left;

        }
        else
        {
            //如果右为空
            //找祖先里面孩子不是祖先的右的那一个
            Node* parent=_node->_parent;
            Node* cur=_node;
            //如果是父亲的右子树,就一直往上走
            //如果parent已经为空,那么就停止循环,parent已经到达了我们的end的位置
            while(parent&&cur==parent->_right)
            {
                cur=cur->_parent;
                parent=parent->_parent;
            }

            _node=parent;
        }
        return *this;
    }

    Self operator++(int)
    {
        Self tmp(*this);

        ++(*this);

        return tmp;
    }
    //前置--
    Self& operator--()
    {

        if(_node->_left)
        {
            //下一个是左子树的最右节点
            Node* right=_node->_left;
            while(right->_right)
            {
                right=right->_right;
            }
            _node=right;
        }
        else
        {
            //孩子不是父亲的左的那个祖先
            Node* parent=_node->_parent;
            Node* cur=_node;
            //如果是父亲的右子树,就一直往上走
            //如果parent已经为空,那么就停止循环,parent已经到达了我们的end的位置
            while(parent&&cur==parent->_left)
            {
                cur=cur->_parent;
                parent=parent->_parent;
            }

            _node=parent;
        }
        return *this;
    }

    Self operator--(int)
    {
        Self tmp(*this);

        --(*this);

        return tmp;
    }
};
//KeyofT将T里面的key取出来
template<class K, class T,class KeyOfT>
struct RBTree
{
    typedef RBTreeNode<T> Node;
public:
    typedef __RBTreeIterator<T,T&,T*> iterator;
    typedef __RBTreeIterator<T,const T&,const T*> const_iterator;

    iterator Begin()
    {
        Node* left=_root;
        while(left&&left->_left)
        {
            left=left->_left;
        }

        return iterator(left);
    }

    iterator End()
    {
        return iterator(nullptr);
    }

    const_iterator Begin() const
    {
        Node* subLeft = _root;
        while (subLeft && subLeft->_left)
        {
            subLeft = subLeft->_left;
        }

        return const_iterator(subLeft);
    }

    const_iterator End() const
    {
        return const_iterator(nullptr);
    }
    //插入和我们的avl树其实是差不多的
    pair<iterator ,bool>Insert(const T&data)
    {
        //实例化仿函数对象
        KeyOfT kot;

        if (_root == nullptr)
        {
            _root = new Node(data);
            //根节点必须是黑色的
            _root->_col = BLACK;
            return make_pair(iterator(_root),true);
        }

        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (kot(cur->_data) < kot(data))
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (kot(cur->_data) > kot(data))
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return make_pair(iterator(cur),true);
            }
        }

        cur = new Node(data);
        Node* newnode=cur;
        //新插入的接地那默认是红色的
        cur->_col=RED;
        if (kot(parent->_data) < kot(data))
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }

        cur->_parent = parent;

        //如果存在parent并且parent的节点的颜色为红色,按照我们不能有两个红色结点连在一起的原则,我们需要进行调整
        while(parent &&parent->_col==RED)
        {
            Node* grandfather=parent->_parent;
            assert(grandfather);
            //父亲是红色的话,祖父结点一定是黑色的,不然我们的红黑树在我们的本次调整之前就已经不满足红黑树的条件了
            assert(grandfather->_col==BLACK);
            // 关键看叔叔
            //父亲是祖父的左
            if (parent == grandfather->_left)
            {
                Node* uncle = grandfather->_right;
                // 情况一 : uncle存在且为红,变色+继续往上处理
                if (uncle && uncle->_col == RED)
                {
                    //父亲和叔叔全部都变成黑色的,把祖父变成红色的
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    // 继续往上处理,将祖父当成cur结点,然后再将cur的父亲找到
                    cur = grandfather;
                    parent = cur->_parent;
                }
                // 情况二+三:uncle不存在 + 存在且为黑
                //看是单旋还是双旋
                else
                {
                    // 情况二:右单旋+变色
                    //     g
                    //   p   u
                    // c
                    //cur是父节点的左子树,左边高,右单旋+变色
                    if (cur == parent->_left)
                    {
                        //对祖父的位置进行右旋
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else
                    {
                        // 情况三:左右单旋+变色
                        //     g
                        //   p   u
                        //     c
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }

                    break;
                }
            }
            //父亲是祖父的右结点
            else // (parent == grandfather->_right)
            {
                Node* uncle = grandfather->_left;
                // 情况一
                if (uncle && uncle->_col == RED)
                {
                    //变色
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    // 继续往上处理
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else
                {
                    // 情况二:左单旋+变色
                    //     g
                    //   u   p
                    //         c
                    if (cur == parent->_right)
                    {
                        RotateL(grandfather);
                        //父亲的颜色变黑,祖父的颜色变红
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else
                    {
                        // 情况三:右左单旋+变色
                        //     g
                        //   u   p
                        //     c
                        //先以parent的位置进行右单旋,然后再祖父结点进行左单旋
                        RotateR(parent);
                        RotateL(grandfather);
                        //cur变黑,祖父变红
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }

                    break;
                }
            }

        }
        //永远将根节点设置为黑色
        _root->_col = BLACK;
        return make_pair(iterator(newnode),true);
    }
    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }

    bool IsBalance()
    {
        //空树可以认为是红黑树
        if (_root == nullptr)
        {
            return true;
        }

        //根节点的颜色一定要是黑色
        if (_root->_col == RED)
        {
            cout << "根节点不是黑色" << endl;
            return false;
        }

        // 黑色节点数量基准值

        int benchmark = 0;
        /*Node* cur = _root;
        while (cur)
        {
        if (cur->_col == BLACK)
        ++benchmark;

        cur = cur->_left;
        }*/

        return PrevCheck(_root, 0, benchmark);
    }
private:
    //在递归中,blackNum记录根节点--大年结点路径上的黑色结点的数量
    //前序递归遍历即可,深度优先遍历,遍历到根节点,返回这一条路径的所有的黑色结点统计出来的数量
    bool PrevCheck(Node* root, int blackNum, int& benchmark)
    {
        if (root == nullptr)
        {
            //cout << blackNum << endl;
            //return;
            if (benchmark == 0)
            {
                //记录黑色结点的数量
                benchmark = blackNum;
                return true;
            }

            if (blackNum != benchmark)
            {
                cout << "某条黑色节点的数量不相等" << endl;
                return false;
            }
            else
            {
                return true;
            }
        }
        //如果是黑色,记录黑色的数量+1
        if (root->_col == BLACK)
        {
            ++blackNum;
        }

        if (root->_col == RED && root->_parent->_col == RED)
        {
            cout << "存在连续的红色节点" << endl;
            return false;
        }

        //递归遍历当前结点的左子树和右子树
        return PrevCheck(root->_left, blackNum, benchmark)
               && PrevCheck(root->_right, blackNum, benchmark);
    }

    void _InOrder(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }

        _InOrder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _InOrder(root->_right);
    }

    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;

        Node* ppNode = parent->_parent;

        subR->_left = parent;
        parent->_parent = subR;

        if (_root == parent)
        {
            _root = subR;
            subR->_parent = nullptr;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subR;
            }
            else
            {
                ppNode->_right = subR;
            }

            subR->_parent = ppNode;
        }

    }

    void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;

        parent->_left = subLR;
        if (subLR)
        {
            subLR->_parent = parent;
        }

        Node* ppNode = parent->_parent;

        subL->_right = parent;
        parent->_parent = subL;

        if (_root == parent)
        {
            _root = subL;
            subL->_parent = nullptr;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subL;
            }
            else
            {
                ppNode->_right = subL;
            }

            subL->_parent = ppNode;
        }

    }
    iterator Find(const K& key)
    {
        Node* cur = _root;
        KeyOfT kot;
        while (cur)
        {
            if (kot(cur->_data) < key)
            {
                cur = cur->_right;
            }
            else if (kot(cur->_data) > key)
            {
                cur = cur->_left;
            }
            else
            {
                return iterator(cur);
            }
        }

        return End();
    }
private:
    //定义根节点的缺省值
    Node* _root = nullptr;
};

#endif //RBTREE_RBTREE_H

2.Map.h

#ifndef RBTREE_MAP_H
#define RBTREE_MAP_H
#include "RBTree.h"
namespace zhuyuan
{
    template<class K, class V>
    class map
    {
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
    public:
        typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
        typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;

        iterator begin()
        {
            return _t.Begin();
        }

        iterator end()
        {
            return _t.End();
        }

        pair<iterator, bool> insert(const pair<K, V>& kv)
        {
            return _t.Insert(kv);
        }

        iterator find(const K& key)
        {
            return _t.Find(key);
        }

        V& operator[](const K& key)
        {
            pair<iterator, bool> ret = insert(make_pair(key, V()));
            return ret.first->second;
        }

    private:
        RBTree<K, pair<K, V>, MapKeyOfT> _t;
    };

    void test_map1()
    {
        map<string, int> m;
        m.insert(make_pair("111", 1));
        m.insert(make_pair("555", 5));
        m.insert(make_pair("333", 3));
        m.insert(make_pair("222", 2));

        map<string, int>::iterator it = m.begin();
        while (it != m.end())
        {
            cout << it->first << ":" << it->second << endl;
            ++it;
        }
        cout << endl;

        for (auto& kv : m)
        {
            cout << kv.first << ":" << kv.second << endl;
        }
        cout << endl;
    }

    void test_map2()
    {
        string arr[] = { "ƻ", "", "ƻ", "", "ƻ", "ƻ", "", "ƻ", "㽶", "ƻ", "㽶" };

        map<string, int> countMap;
        for (auto& str : arr)
        {
            countMap[str]++;
        }

        for (const auto& kv : countMap)
        {
            cout << kv.first << ":" << kv.second << endl;
        }
    }

    void test_map3()
    {
        map<string, string> dict;
        dict["insert"];
        dict["insert"] = "";
        dict["left"] = "";

    }
}
#endif //RBTREE_MAP_H

3.set.h

#ifndef RBTREE_SET_H
#define RBTREE_SET_H
#include "RBTree.h"
namespace zhuyuan
{
    template<class K>
    class set
    {
        struct SetKeyOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };
    public:
        typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
        typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

        iterator begin()
        {
            return _t.Begin();
        }

        iterator end()
        {
            return _t.End();
        }

        pair<iterator, bool> insert(const K& key)
        {
            //pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
            auto ret = _t.Insert(key);
            return pair<iterator, bool>(iterator(ret.first._node), ret.second);
        }

        iterator find(const K& key)
        {
            return _t.Find(key);
        }
    private:
        RBTree<K, K, SetKeyOfT> _t;
    };

    void test_set1()
    {
        set<int> s;
        s.insert(8);
        s.insert(6);
        s.insert(11);
        s.insert(5);
        s.insert(6);
        s.insert(7);
        s.insert(10);
        s.insert(13);
        s.insert(12);
        s.insert(15);

        set<int>::iterator it = s.begin();
        while (it != s.end())
        {
            cout << *it << " ";
            ++it;
        }
        cout << endl;

        for (auto e : s)
        {
            cout << e << " ";
        }
        cout << endl;
    }

    }
}
#endif //RBTREE_SET_H

4.main.cpp

#include <iostream>
#include <assert.h>
#include <utility>
using namespace std;
#include "RBTree.h"
#include "Map.h"
#include "Set.h"
int main() {
//    zhuyuan::test_map1();
//    zhuyuan::test_map2();
//    zhuyuan::test_map3();
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桜キャンドル淵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值