红黑树(RED-BLACK TREE)


img

红黑树(RED-BLACK TREE)

1、红黑树概念

红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,通常用于实现动态集合(如集合、映射等)的数据结构。它在插入、删除等操作后可以通过一系列的旋转和颜色变换来保持其平衡性,从而保证了在最坏情况下的时间复杂度为O(log n),其中n是树中元素的个数。

红黑树具有以下特性:

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点是黑色的。
  3. 每个叶子节点(NIL节点,即空节点)是黑色的。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的,并且它的双亲结点也是黑的,即不存在两个连续的红色结点。
  5. 对于任意节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点(即,黑色节点的高度相同)。

总结一下就是(咸鱼老师的结论):左根右,根叶黑,不红红,黑路同

这些特性保证了红黑树的关键性质:任意一条从根到叶子的路径的长度不会超过其他路径的两倍长,从而保证了树的平衡性。

红黑树通常用于实现诸如集合、映射等数据结构,例如在C++的STL中的std::mapstd::set就是基于红黑树实现的。


2、红黑树的实现

前面一篇博客有写平衡二叉树(AVL树)的实现,这里红黑树的实现和平衡二叉树(AVL树)类似。

2.1、红黑树的结点定义

这里我们将红黑树的结点的值定义为键值对(Key,Value),当然也可以只定义为单值Key。相对于平衡二叉树少了平衡因子,多了颜色

enum Colour {
    RED,
    BLACK
};

template<class K, class V>
struct RBTreeNode {
    typedef RBTreeNode<K, V> Node;
    Node *_left;
    Node *_right;
    Node *_parent;
    Colour _col;

    pair<K, V> _kv;

    RBTreeNode(const pair<K, V> &kv) : _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _kv(kv) {}
};

这里我们默认给新插入的结点的颜色设置为红色。原因是新增的结点如果颜色是黑色,那么一定会导致parent左右子树的黑结点总数不一样,就必须得调整;新增的结点如果颜色是红色,那么parent左右子树的黑结点总数还是一样的吗,如果parent的颜色的黑色,就不用调整!


2.2、红黑树的插入

红黑树的插入可以分为两步:

  1. 按二叉搜索树进行插入
  • 之前的二叉搜索树代码:这里将K模型变为了KV模型。
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);
        if (parent->_kv.first > cur->_kv.first)
            parent->_left = cur;
        else
            parent->_right = cur;
				return true;
}

简单修改一下,确定初步思路:

bool Insert(const pair<K, V> &kv) {
    Node *cur = _root;
    Node *parent = nullptr;
    if (cur == nullptr) {
        Node *newNode = new Node(key);
        _root = newNode;
        return true;
    }
    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 == nullptr
    cur = new Node(kv);
    if (parent->_kv.first < kv.first)
      parent->_right = cur;
    else if (parent->_kv.first > kv.first)
      parent->_left = cur;

    cur->_parent = parent;// 这里是新增的代码,用来记录当前结点的双亲,以便后续进行向上迭代

  	// 判断当前插入新结点后会不会导致红黑树树变得不平衡
  	// 此处是代码
    return true;
}
  1. 检查插入新结点后会不会导致红黑树的性质得到破坏
  • 因为新结点是红色,如果其双亲是黑色结点,那么则不破坏红黑树的性质,不需要调整;如果其双亲是红色结点,那么则破坏了不红红的性质,需要做出调整,主要分为两种情况:

    情况一:u存在且颜色为红。

    u是uncle,g是grandfather,p是parent,cur就是当前结点。

    那么当前u、g、p、cur的颜色是确定的(根据红黑树性质:左根右,根叶黑,不红红,黑路同)。即cur红,p红,g黑,u红。注意,这个cur可能是新增结点,也肯是由下往上调整时由黑变过来的。但是并不影响调整规则。

    调整方案:p和u变黑,g变红,然后继续向上检查(因为当前子树的根结点还是红(g),还可能导致连续的两个红结点)。

    那么代码变为如下:while结束条件为parent为空或者parent的颜色为黑。并且我们得记录u是g的左结点还是右结点,以便于后续的旋转调整(确定是L、R、LR、RL旋转的一个)。

    这里提示一点:只要我们知道L、LR的调整方案,那么R、RL得到调整方案也很容易知道,因为这两个调整方案的对称的。

    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);
            if (parent->_kv.first > cur->_kv.first)
                parent->_left = cur;
            else
                parent->_right = cur;
    
            cur->_parent = parent;
    
            while (parent && parent->_col == RED) {
    
                // 记录祖父结点
                Node *grandfather = parent->_parent;
    
                // 记录祖父结点
                if (parent == grandfather->_left) {
                    Node *uncle = grandfather->_right;
    
                    // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                    // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                    if (uncle && uncle->_col == RED) {
                        parent->_col = uncle->_col = BLACK;
                        grandfather->_col = RED;
    
                        //继续往上检查
                        cur = grandfather;
                        parent = cur->_parent;// 注意别写反了
                    } else {
                        // 情况二:叔叔不存在或者叔叔存在且为黑
                        
                      	// 以下是代码
    
                } else {
                    Node *uncle = grandfather->_left;
                    // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                    // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                    if (uncle && uncle->_col == RED) {
                        parent->_col = uncle->_col = BLACK;
                        grandfather->_col = RED;
    
                        //继续往上检查
                        cur = grandfather;
                        parent = cur->_parent;// 注意别写反了
                    } else {
                        // 情况二:叔叔不存在或者叔叔存在且为黑
                  
                      	// 以下是代码
                      
                    }
                }
            }
            _root->_col = BLACK; // 根结点始终为黑
            return true;
    }
    

    情况二:u不存在或者存在且颜色为黑。

    这个情况有点复杂,我们放到下面的红黑树的旋转中讲解。


2.3、红黑树的旋转

上面讲到情况二:u不存在或者存在且颜色为黑。这个时候存在四种形态:但是每个形态的调整规则都是一样的,不区分u不存在或者存在且颜色为黑。

形态一:p为g的左结点,cur为p的左结点,这个时候需要右单旋。

形态二:p为g的右结点,cur为p的右结点,这个时候需要左单旋。

形态三:p为g的左结点,cur为p的右结点,这个时候需要先左单旋再右单旋。

形态四:p为g的右结点,cur为p的左结点,这个时候需要先右单旋再左单旋。

看完这四种形态,是不是觉得和AVL树很像!并且下面代码用到的左单旋和右单旋的代码都是用的AVL树的,只不过不再需要平衡因子了!

这里声明一个点:下面的所有抽象图,在插入新结点之前,每条路径的最低一层的黑色结点都是代表一棵具有n(可以是0,12,3…)个黑色结点的树,多少个黑色结点不影响调整规则。

2.3.1、右单旋(R旋转)

形态一:p为g的左结点,cur为p的左结点,这个时候需要右单旋。

u是uncle,g是grandfather,p是parent,cur就是当前结点。

调整方案:以g结点进行右单旋,然后p变黑,g变红,然后调整结束,不必再向上检查(因为当前子树的根结点是黑(p),不再可能导致连续的两个红结点)。

代码变为如下:

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);
        if (parent->_kv.first > cur->_kv.first)
            parent->_left = cur;
        else
            parent->_right = cur;

        cur->_parent = parent;

        while (parent && parent->_col == RED) {

            // 记录祖父结点
            Node *grandfather = parent->_parent;

            // 记录祖父结点
            if (parent == grandfather->_left) {
                Node *uncle = grandfather->_right;

                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑
                    
                  	//  形状一
                    //               g
                    //        p               u
                    //  cur
                    if (cur == parent->_left) {
                        // 这时候只需要右旋
                        RotateR(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状三
                      
                    }
							break; // 旋转完加变色,不需要再调整
            } else {
                Node *uncle = grandfather->_left;
                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑
              
                  	// 以下是代码
                  
                }
            }
        }
        _root->_col = BLACK; // 根结点始终为黑
        return true;
}

2.3.2、左单旋(L旋转)

形态二:p为g的右结点,cur为p的右结点,这个时候需要左单旋。

u是uncle,g是grandfather,p是parent,cur就是当前结点。

调整方案:以g结点进行左单旋,然后p变黑,g变红,然后调整结束,不必再向上检查(因为当前子树的根结点是黑(p),不再可能导致连续的两个红结点)。

这里不再花抽象图,自行根据上述右单旋画。这里仅贴代码:其实根据对称,代码也很好写。

代码变为如下:

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);
       if (parent->_kv.first > cur->_kv.first)
           parent->_left = cur;
       else
           parent->_right = cur;

       cur->_parent = parent;

       while (parent && parent->_col == RED) {

           // 记录祖父结点
           Node *grandfather = parent->_parent;

           // 记录祖父结点
           if (parent == grandfather->_left) {
               Node *uncle = grandfather->_right;

               // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
               // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
               if (uncle && uncle->_col == RED) {
                   parent->_col = uncle->_col = BLACK;
                   grandfather->_col = RED;

                   //继续往上检查
                   cur = grandfather;
                   parent = cur->_parent;// 注意别写反了
               } else {
                   // 情况二:叔叔不存在或者叔叔存在且为黑
                   
                 	//  形状一
                   //               g
                   //        p               u
                   //  cur
                   if (cur == parent->_left) {
                       // 这时候只需要右旋
                       RotateR(grandfather);
                       //只要父亲和祖父变色
                       parent->_col = BLACK;
                       grandfather->_col = RED;
                   } else {
                       //形状三
                     
                   }
							break; // 旋转完加变色,不需要再调整
           } else {
               Node *uncle = grandfather->_left;
               // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
               // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
               if (uncle && uncle->_col == RED) {
                   parent->_col = uncle->_col = BLACK;
                   grandfather->_col = RED;

                   //继续往上检查
                   cur = grandfather;
                   parent = cur->_parent;// 注意别写反了
               } else {
                   // 情况二:叔叔不存在或者叔叔存在且为黑
             
                 	//  形状二
                   //               g
                   //        u               p
                   //                              cur
                   if (cur == parent->_right) {
                       // 这时候只需要左旋
                       RotateL(grandfather);
                       //只要父亲和祖父变色
                       parent->_col = BLACK;
                       grandfather->_col = RED;
                   } else {
                       //形状四
                   }
                 break; // 旋转完加变色,不需要再调整
               }
           }
       }
       _root->_col = BLACK; // 根结点始终为黑
       return true;
}

2.3.3、先左单旋再右单旋(LR旋转)

形态三:p为g的左结点,cur为p的右结点,这个时候需要先左单旋再右单旋。

u是uncle,g是grandfather,p是parent,cur就是当前结点。

调整方案:先以p结点进行左单旋,然后以g结点进行右单旋,最后cur变黑,g变红,然后调整结束,不必再向上检查(因为当前子树的根结点是黑(cur),不再可能导致连续的两个红结点)。

代码变为如下:

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);
        if (parent->_kv.first > cur->_kv.first)
            parent->_left = cur;
        else
            parent->_right = cur;

        cur->_parent = parent;

        while (parent && parent->_col == RED) {

            // 记录祖父结点
            Node *grandfather = parent->_parent;

            // 记录祖父结点
            if (parent == grandfather->_left) {
                Node *uncle = grandfather->_right;

                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑
                    
                  	//  形状一
                    //               g
                    //        p               u
                    //  cur
                    if (cur == parent->_left) {
                        // 这时候只需要右旋
                        RotateR(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状三
                        //               g
                        //        p               u
                        //            cur

                        // 这时候需要先左旋再右旋
                        // p位置左旋
                        // 再g位置右旋
                        RotateL(parent);
                        RotateR(grandfather);

                        //p和g位置变色
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
							break; // 旋转完加变色,不需要再调整
            } else {
                Node *uncle = grandfather->_left;
                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑
              
                  	//  形状二
                    //               g
                    //        u               p
                    //                              cur
                    if (cur == parent->_right) {
                        // 这时候只需要左旋
                        RotateL(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状四
                    }
                  break; // 旋转完加变色,不需要再调整
                }
            }
        }
        _root->_col = BLACK; // 根结点始终为黑
        return true;
}

2.3.4、先右单旋再左单旋(RL旋转)

形态四:p为g的右结点,cur为p的左结点,这个时候需要先右单旋再左单旋。

u是uncle,g是grandfather,p是parent,cur就是当前结点。

调整方案:先以p结点进行右单旋,然后以g结点进行左单旋,最后cur变黑,g变红,然后调整结束,不必再向上检查(因为当前子树的根结点是黑(cur),不再可能导致连续的两个红结点)。

这里不再花抽象图,自行根据上述右单旋画。这里仅贴代码:其实根据对称,代码也很好写。

代码变为如下:

    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);
        if (parent->_kv.first > cur->_kv.first)
            parent->_left = cur;
        else
            parent->_right = cur;

        cur->_parent = parent;

        while (parent && parent->_col == RED) {

            // 记录祖父结点
            Node *grandfather = parent->_parent;

            // 记录祖父结点
            if (parent == grandfather->_left) {
                Node *uncle = grandfather->_right;

                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑

                    //  形状一
                    //               g
                    //        p               u
                    //  cur
                    if (cur == parent->_left) {
                        // 这时候只需要右旋
                        RotateR(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状三
                        //               g
                        //        p               u
                        //            cur

                        // 这时候需要先左旋再右旋
                        // p位置左旋
                        // 再g位置右旋
                        RotateL(parent);
                        RotateR(grandfather);

                        //p和g位置变色
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break; // 旋转完加变色,不需要再调整
                }

            } else {
                Node *uncle = grandfather->_left;
                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑

                    //  形状二
                    //               g
                    //        u               p
                    //                              cur
                    if (cur == parent->_right) {
                        // 这时候只需要左旋
                        RotateL(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状四
                        //               g
                        //        u               p
                        //                   cur

                        // 这时候需要先右旋再左旋
                        // p位置右旋
                        // 再g位置左旋
                        RotateR(parent);
                        RotateL(grandfather);

                        //p和g位置变色
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break; // 旋转完加变色,不需要再调整
                }
            }
        }
        _root->_col = BLACK; // 根结点始终为黑
        return true;
    }

2.4、红黑树的插入完整代码

需要注意的是:再进行了旋转加变色后,当前子树的根结点都变为了黑色,不再存在连续的红色结点,因此可以直接退出调整,即跳出while循环。

    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);
        if (parent->_kv.first > cur->_kv.first)
            parent->_left = cur;
        else
            parent->_right = cur;

        cur->_parent = parent;

        while (parent && parent->_col == RED) {

            // 记录祖父结点
            Node *grandfather = parent->_parent;

            // 记录祖父结点
            if (parent == grandfather->_left) {
                Node *uncle = grandfather->_right;

                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑

                    //  形状一
                    //               g
                    //        p               u
                    //  cur
                    if (cur == parent->_left) {
                        // 这时候只需要右旋
                        RotateR(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状三
                        //               g
                        //        p               u
                        //            cur

                        // 这时候需要先左旋再右旋
                        // p位置左旋
                        // 再g位置右旋
                        RotateL(parent);
                        RotateR(grandfather);

                        //p和g位置变色
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break; // 旋转完加变色,不需要再调整
                }

            } else {
                Node *uncle = grandfather->_left;
                // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;

                    //继续往上检查
                    cur = grandfather;
                    parent = cur->_parent;// 注意别写反了
                } else {
                    // 情况二:叔叔不存在或者叔叔存在且为黑

                    //  形状二
                    //               g
                    //        u               p
                    //                              cur
                    if (cur == parent->_right) {
                        // 这时候只需要左旋
                        RotateL(grandfather);
                        //只要父亲和祖父变色
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        //形状四
                        //               g
                        //        u               p
                        //                   cur

                        // 这时候需要先右旋再左旋
                        // p位置右旋
                        // 再g位置左旋
                        RotateR(parent);
                        RotateL(grandfather);

                        //p和g位置变色
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break; // 旋转完加变色,不需要再调整
                }
            }
        }
        _root->_col = BLACK; // 根结点始终为黑
        return true;
    }

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

        parent->_right = subRL;
        subR->_left = parent;
        Node *ppnode = parent->_parent;

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



        // 如果当前parent本身就是跟结点的话,我们得把根结点更新
        if (parent == _root) {
            _root = subR;
            subR->_parent = nullptr;
        } else {
            if (parent == ppnode->_left) {
                // subR链接上之前的爷爷结点
                ppnode->_left = subR;
            } else {
                // subR链接上之前的爷爷结点
                ppnode->_right = subR;
            }
            subR->_parent = ppnode;
        }
    }

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

        parent->_left = subLR;
        subL->_right = parent;
        Node *ppnode = parent->_parent;

        if (subLR)
            subLR->_parent = parent;
        parent->_parent = subL;



        // 如果当前parent本身就是跟结点的话,我们得把根结点更新
        if (parent == _root) {
            _root = subL;
            subL->_parent = nullptr;
        } else {
            if (parent == ppnode->_left) {
                // subR链接上之前的爷爷结点
                ppnode->_left = subL;
            } else {
                // subR链接上之前的爷爷结点
                ppnode->_right = subL;
            }
            subL->_parent = ppnode;
        }
    }

3、红黑树的验证

  1. 验证其为搜索二叉树
    • 中序遍历该红黑树,如果是有序说明是搜索二叉树。
  2. 验证其是否满足红黑树的性质
    • 左根右,根叶黑,不红红,黑路同。
bool _Check(Node *cur, int blackNum, int refBlackNum) {
        if (cur == nullptr) {
            if (blackNum != refBlackNum) {
                cout << "黑结点数量不一样" << endl;
                return false;// 到空结点开始比较黑结点是不是一样
            }

            cout << blackNum << endl;
            return true;
}

bool IsBalance() {
        if (_root && _root->_col == RED)
            return false;
        int refBlackNum = 0; // 每条路径黑色结点的个数,这里以最右边的路径黑色结点的个数为基准
        Node *cur = _root;
        while (cur) {
            if (cur->_col == BLACK)
                ++refBlackNum;
            cur = cur->_right;
        }
        return _Check(_root, 0, refBlackNum);
}

4、红黑树的删除(了解)

红黑树的删除比较难,这里仅贴代码。

    bool Remove(const K &key) {
        Node *target = Find(key);
        if (!target) // 如果没找到目标结点,则返回false
            return false;

        // 执行删除操作
        Node *to_fix = nullptr; // 用于记录需要修正的结点
        Node *parent = target->_parent;
        Colour target_original_colour = target->_col;
        Node *child;
        if (!target->_left) {
            child = target->_right;
            Transplant(target, target->_right);
        } else if (!target->_right) {
            child = target->_left;
            Transplant(target, target->_left);
        } else {
            Node *successor = Minimum(target->_right); // 找到右子树中的最小结点作为后继结点
            target_original_colour = successor->_col;
            child = successor->_right;
            if (successor->_parent == target)
                child->_parent = successor;
            else {
                Transplant(successor, successor->_right);
                successor->_right = target->_right;
                successor->_right->_parent = successor;
            }
            Transplant(target, successor);
            successor->_left = target->_left;
            successor->_left->_parent = successor;
            successor->_col = target->_col;
        }
        delete target;

        // 修正红黑树性质
        if (target_original_colour == BLACK)
            FixAfterDelete(parent, child);
        return true;
    }


    void FixAfterDelete(Node *parent, Node *node) {
        while (node != _root && (!node || node->_col == BLACK)) {
            if (node == parent->_left) {
                Node *sibling = parent->_right;
                if (sibling->_col == RED) {
                    sibling->_col = BLACK;
                    parent->_col = RED;
                    RotateL(parent);
                    sibling = parent->_right;
                }
                if ((!sibling->_left || sibling->_left->_col == BLACK) &&
                    (!sibling->_right || sibling->_right->_col == BLACK)) {
                    sibling->_col = RED;
                    node = parent;
                    parent = parent->_parent;
                } else {
                    if (!sibling->_right || sibling->_right->_col == BLACK) {
                        sibling->_left->_col = BLACK;
                        sibling->_col = RED;
                        RotateR(sibling);
                        sibling = parent->_right;
                    }
                    sibling->_col = parent->_col;
                    parent->_col = BLACK;
                    sibling->_right->_col = BLACK;
                    RotateL(parent);
                    node = _root;
                }
            } else {
                Node *sibling = parent->_left;
                if (sibling->_col == RED) {
                    sibling->_col = BLACK;
                    parent->_col = RED;
                    RotateR(parent);
                    sibling = parent->_left;
                }
                if ((!sibling->_right || sibling->_right->_col == BLACK) &&
                    (!sibling->_left || sibling->_left->_col == BLACK)) {
                    sibling->_col = RED;
                    node = parent;
                    parent = parent->_parent;
                } else {
                    if (!sibling->_left || sibling->_left->_col == BLACK) {
                        sibling->_right->_col = BLACK;
                        sibling->_col = RED;
                        RotateL(sibling);
                        sibling = parent->_left;
                    }
                    sibling->_col = parent->_col;
                    parent->_col = BLACK;
                    sibling->_left->_col = BLACK;
                    RotateR(parent);
                    node = _root;
                }
            }
        }
        if (node)
            node->_col = BLACK;
    }


    Node *Minimum(Node *node) const {
        while (node->_left)
            node = node->_left;
        return node;
    }


    void Transplant(Node *u, Node *v) {
        if (!u->_parent)
            _root = v;
        else if (u == u->_parent->_left)
            u->_parent->_left = v;
        else
            u->_parent->_right = v;
        if (v)
            v->_parent = u->_parent;
    }

5、红黑树的性能

红黑树在各种操作的性能表现上都比较稳定,其时间复杂度如下:

  1. 查找:红黑树的查找操作与二叉搜索树类似,时间复杂度为 O(log n),其中 n 为红黑树中元素的数量。

  2. 插入:插入操作可能会引起红黑树的结构变化,但是由于红黑树的平衡性质,插入操作的最坏情况时间复杂度也是 O(log n)。

  3. 删除:与插入操作类似,删除操作可能会引起红黑树的结构变化,但由于红黑树的平衡性质,删除操作的最坏情况时间复杂度也是 O(log n)。

相比于普通的二叉搜索树,红黑树在插入和删除操作上引入了一些额外的平衡维护操作,但这些操作的时间复杂度都是常数级别的,对整体性能的影响较小。因此,红黑树在实践中通常表现良好,并且被广泛应用在需要高效插入、删除和查找操作的场景中,比如 C++ STL 中的 std::mapstd::set,后面我们模拟实现map和set可以看到。


6、红黑树的整体代码

  • RBTree.h文件
enum Colour {
   RED,
   BLACK
};

template<class K, class V>
struct RBTreeNode {
   typedef RBTreeNode<K, V> Node;
   Node *_left;
   Node *_right;
   Node *_parent;
   Colour _col;

   pair<K, V> _kv;

   RBTreeNode(const pair<K, V> &kv) : _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _kv(kv) {}
};


template<class K, class V>
class RBTree {
   typedef RBTreeNode<K, V> Node;
public:

   // 红黑树的查找
   Node *Find(const K &key) const {
       Node *cur = _root;
       while (cur) {
           if (cur->_kv.first < key)
               cur = cur->_right;
           else if (cur->_kv.first > key)
               cur = cur->_left;
           else
               return cur; // 找到了目标结点
       }
       return nullptr; // 没找到目标结点
   }


   // 红黑树的删除

   bool Remove(const K &key) {
       Node *target = Find(key);
       if (!target) // 如果没找到目标结点,则返回false
           return false;

       // 执行删除操作
       Node *to_fix = nullptr; // 用于记录需要修正的结点
       Node *parent = target->_parent;
       Colour target_original_colour = target->_col;
       Node *child;
       if (!target->_left) {
           child = target->_right;
           Transplant(target, target->_right);
       } else if (!target->_right) {
           child = target->_left;
           Transplant(target, target->_left);
       } else {
           Node *successor = Minimum(target->_right); // 找到右子树中的最小结点作为后继结点
           target_original_colour = successor->_col;
           child = successor->_right;
           if (successor->_parent == target)
               child->_parent = successor;
           else {
               Transplant(successor, successor->_right);
               successor->_right = target->_right;
               successor->_right->_parent = successor;
           }
           Transplant(target, successor);
           successor->_left = target->_left;
           successor->_left->_parent = successor;
           successor->_col = target->_col;
       }
       delete target;

       // 修正红黑树性质
       if (target_original_colour == BLACK)
           FixAfterDelete(parent, child);
       return true;
   }


   void FixAfterDelete(Node *parent, Node *node) {
       while (node != _root && (!node || node->_col == BLACK)) {
           if (node == parent->_left) {
               Node *sibling = parent->_right;
               if (sibling->_col == RED) {
                   sibling->_col = BLACK;
                   parent->_col = RED;
                   RotateL(parent);
                   sibling = parent->_right;
               }
               if ((!sibling->_left || sibling->_left->_col == BLACK) &&
                   (!sibling->_right || sibling->_right->_col == BLACK)) {
                   sibling->_col = RED;
                   node = parent;
                   parent = parent->_parent;
               } else {
                   if (!sibling->_right || sibling->_right->_col == BLACK) {
                       sibling->_left->_col = BLACK;
                       sibling->_col = RED;
                       RotateR(sibling);
                       sibling = parent->_right;
                   }
                   sibling->_col = parent->_col;
                   parent->_col = BLACK;
                   sibling->_right->_col = BLACK;
                   RotateL(parent);
                   node = _root;
               }
           } else {
               Node *sibling = parent->_left;
               if (sibling->_col == RED) {
                   sibling->_col = BLACK;
                   parent->_col = RED;
                   RotateR(parent);
                   sibling = parent->_left;
               }
               if ((!sibling->_right || sibling->_right->_col == BLACK) &&
                   (!sibling->_left || sibling->_left->_col == BLACK)) {
                   sibling->_col = RED;
                   node = parent;
                   parent = parent->_parent;
               } else {
                   if (!sibling->_left || sibling->_left->_col == BLACK) {
                       sibling->_right->_col = BLACK;
                       sibling->_col = RED;
                       RotateL(sibling);
                       sibling = parent->_left;
                   }
                   sibling->_col = parent->_col;
                   parent->_col = BLACK;
                   sibling->_left->_col = BLACK;
                   RotateR(parent);
                   node = _root;
               }
           }
       }
       if (node)
           node->_col = BLACK;
   }


   Node *Minimum(Node *node) const {
       while (node->_left)
           node = node->_left;
       return node;
   }


   void Transplant(Node *u, Node *v) {
       if (!u->_parent)
           _root = v;
       else if (u == u->_parent->_left)
           u->_parent->_left = v;
       else
           u->_parent->_right = v;
       if (v)
           v->_parent = u->_parent;
   }


   // 红黑树的插入
   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);
       if (parent->_kv.first > cur->_kv.first)
           parent->_left = cur;
       else
           parent->_right = cur;

       cur->_parent = parent;

       while (parent && parent->_col == RED) {

           // 记录祖父结点
           Node *grandfather = parent->_parent;

           // 记录祖父结点
           if (parent == grandfather->_left) {
               Node *uncle = grandfather->_right;

               // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
               // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
               if (uncle && uncle->_col == RED) {
                   parent->_col = uncle->_col = BLACK;
                   grandfather->_col = RED;

                   //继续往上检查
                   cur = grandfather;
                   parent = cur->_parent;// 注意别写反了
               } else {
                   // 情况二:叔叔不存在或者叔叔存在且为黑

                   //  形状一
                   //               g
                   //        p               u
                   //  cur
                   if (cur == parent->_left) {
                       // 这时候只需要右旋
                       RotateR(grandfather);
                       //只要父亲和祖父变色
                       parent->_col = BLACK;
                       grandfather->_col = RED;
                   } else {
                       //形状三
                       //               g
                       //        p               u
                       //            cur

                       // 这时候需要先左旋再右旋
                       // p位置左旋
                       // 再g位置右旋
                       RotateL(parent);
                       RotateR(grandfather);

                       //p和g位置变色
                       cur->_col = BLACK;
                       grandfather->_col = RED;
                   }
                   break; // 旋转完加变色,不需要再调整
               }

           } else {
               Node *uncle = grandfather->_left;
               // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
               // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
               if (uncle && uncle->_col == RED) {
                   parent->_col = uncle->_col = BLACK;
                   grandfather->_col = RED;

                   //继续往上检查
                   cur = grandfather;
                   parent = cur->_parent;// 注意别写反了
               } else {
                   // 情况二:叔叔不存在或者叔叔存在且为黑

                   //  形状二
                   //               g
                   //        u               p
                   //                              cur
                   if (cur == parent->_right) {
                       // 这时候只需要左旋
                       RotateL(grandfather);
                       //只要父亲和祖父变色
                       parent->_col = BLACK;
                       grandfather->_col = RED;
                   } else {
                       //形状四
                       //               g
                       //        u               p
                       //                   cur

                       // 这时候需要先右旋再左旋
                       // p位置右旋
                       // 再g位置左旋
                       RotateR(parent);
                       RotateL(grandfather);

                       //p和g位置变色
                       cur->_col = BLACK;
                       grandfather->_col = RED;
                   }
                   break; // 旋转完加变色,不需要再调整
               }
           }
       }
       _root->_col = BLACK; // 根结点始终为黑
       return true;
   }

   void InOrder() {
       return _InOrder(_root);
   }

   bool IsBalance() {
       if (_root && _root->_col == RED)
           return false;
       int refBlackNum = 0; // 每条路径黑色结点的个数,这里以最右边的路径黑色结点的个数为基准
       Node *cur = _root;
       while (cur) {
           if (cur->_col == BLACK)
               ++refBlackNum;
           cur = cur->_right;
       }
       return _Check(_root, 0, refBlackNum);
   }

private:
   Node *_root = nullptr;

   bool _Check(Node *cur, int blackNum, int refBlackNum) {
       if (cur == nullptr) {
           if (blackNum != refBlackNum) {
               cout << "黑结点数量不一样" << endl;
               return false;// 到空结点开始比较黑结点是不是一样
           }

           cout << blackNum << endl;
           return true;
       }

       if (cur->_col == RED && cur->_parent->_col == RED) {
           cout << "存在连续红结点:" << cur->_kv.first << endl;
           return false;
       }

       if (cur->_col == BLACK)
           ++blackNum; // 统计该条路径的黑结点个数


       return _Check(cur->_left, blackNum, refBlackNum) && _Check(cur->_right, blackNum, refBlackNum);
   }

   void _InOrder(Node *root) {
       if (root == nullptr)
           return;
       _InOrder(root->_left);
       cout << root->_kv.first << endl;
       _InOrder(root->_right);
   }

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

       parent->_right = subRL;
       subR->_left = parent;
       Node *ppnode = parent->_parent;

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

       // 如果当前parent本身就是跟结点的话,我们得把根结点更新
       if (parent == _root) {
           _root = subR;
           subR->_parent = nullptr;
       } else {
           if (parent == ppnode->_left) {
               // subR链接上之前的爷爷结点
               ppnode->_left = subR;
           } else {
               // subR链接上之前的爷爷结点
               ppnode->_right = subR;
           }
           subR->_parent = ppnode;
       }
   }

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

       parent->_left = subLR;
       subL->_right = parent;
       Node *ppnode = parent->_parent;

       if (subLR)
           subLR->_parent = parent;
       parent->_parent = subL;

       // 如果当前parent本身就是跟结点的话,我们得把根结点更新
       if (parent == _root) {
           _root = subL;
           subL->_parent = nullptr;
       } else {
           if (parent == ppnode->_left) {
               // subR链接上之前的爷爷结点
               ppnode->_left = subL;
           } else {
               // subR链接上之前的爷爷结点
               ppnode->_right = subL;
           }
           subL->_parent = ppnode;
       }
   }
};

7、二叉搜索树、AVL树和红黑树的性能对比(插入、查找、旋转(AVL和红黑树))

  • RBTree.h文件

    //
    // Created by 徐鹏 on 2024/3/31.
    //
    
    #ifndef DEMO_05_RBTREE_H
    #define DEMO_05_RBTREE_H
    
    #endif //DEMO_05_RBTREE_H
    
    #include <iostream>
    
    using namespace std;
    
    enum Colour {
        RED,
        BLACK
    };
    
    template<class K, class V>
    struct RBTreeNode {
        typedef RBTreeNode<K, V> Node;
        Node *_left;
        Node *_right;
        Node *_parent;
        Colour _col;
    
        pair<K, V> _kv;
    
        RBTreeNode(const pair<K, V> &kv) : _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _kv(kv) {}
    };
    
    
    template<class K, class V>
    class RBTree {
        typedef RBTreeNode<K, V> Node;
    public:
    
        // 红黑树的查找
        Node *Find(const K &key) const {
            Node *cur = _root;
            while (cur) {
                if (cur->_kv.first < key)
                    cur = cur->_right;
                else if (cur->_kv.first > key)
                    cur = cur->_left;
                else
                    return cur; // 找到了目标结点
            }
            return nullptr; // 没找到目标结点
        }
    
    
        // 红黑树的删除
    
        bool Remove(const K &key) {
            Node *target = Find(key);
            if (!target) // 如果没找到目标结点,则返回false
                return false;
    
            // 执行删除操作
            Node *to_fix = nullptr; // 用于记录需要修正的结点
            Node *parent = target->_parent;
            Colour target_original_colour = target->_col;
            Node *child;
            if (!target->_left) {
                child = target->_right;
                Transplant(target, target->_right);
            } else if (!target->_right) {
                child = target->_left;
                Transplant(target, target->_left);
            } else {
                Node *successor = Minimum(target->_right); // 找到右子树中的最小结点作为后继结点
                target_original_colour = successor->_col;
                child = successor->_right;
                if (successor->_parent == target)
                    child->_parent = successor;
                else {
                    Transplant(successor, successor->_right);
                    successor->_right = target->_right;
                    successor->_right->_parent = successor;
                }
                Transplant(target, successor);
                successor->_left = target->_left;
                successor->_left->_parent = successor;
                successor->_col = target->_col;
            }
            delete target;
    
            // 修正红黑树性质
            if (target_original_colour == BLACK)
                FixAfterDelete(parent, child);
            return true;
        }
    
    
        void FixAfterDelete(Node *parent, Node *node) {
            while (node != _root && (!node || node->_col == BLACK)) {
                if (node == parent->_left) {
                    Node *sibling = parent->_right;
                    if (sibling->_col == RED) {
                        sibling->_col = BLACK;
                        parent->_col = RED;
                        RotateL(parent);
                        sibling = parent->_right;
                    }
                    if ((!sibling->_left || sibling->_left->_col == BLACK) &&
                        (!sibling->_right || sibling->_right->_col == BLACK)) {
                        sibling->_col = RED;
                        node = parent;
                        parent = parent->_parent;
                    } else {
                        if (!sibling->_right || sibling->_right->_col == BLACK) {
                            sibling->_left->_col = BLACK;
                            sibling->_col = RED;
                            RotateR(sibling);
                            sibling = parent->_right;
                        }
                        sibling->_col = parent->_col;
                        parent->_col = BLACK;
                        sibling->_right->_col = BLACK;
                        RotateL(parent);
                        node = _root;
                    }
                } else {
                    Node *sibling = parent->_left;
                    if (sibling->_col == RED) {
                        sibling->_col = BLACK;
                        parent->_col = RED;
                        RotateR(parent);
                        sibling = parent->_left;
                    }
                    if ((!sibling->_right || sibling->_right->_col == BLACK) &&
                        (!sibling->_left || sibling->_left->_col == BLACK)) {
                        sibling->_col = RED;
                        node = parent;
                        parent = parent->_parent;
                    } else {
                        if (!sibling->_left || sibling->_left->_col == BLACK) {
                            sibling->_right->_col = BLACK;
                            sibling->_col = RED;
                            RotateL(sibling);
                            sibling = parent->_left;
                        }
                        sibling->_col = parent->_col;
                        parent->_col = BLACK;
                        sibling->_left->_col = BLACK;
                        RotateR(parent);
                        node = _root;
                    }
                }
            }
            if (node)
                node->_col = BLACK;
        }
    
    
        Node *Minimum(Node *node) const {
            while (node->_left)
                node = node->_left;
            return node;
        }
    
    
        void Transplant(Node *u, Node *v) {
            if (!u->_parent)
                _root = v;
            else if (u == u->_parent->_left)
                u->_parent->_left = v;
            else
                u->_parent->_right = v;
            if (v)
                v->_parent = u->_parent;
        }
    
    
        // 红黑树的插入
        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);
            if (parent->_kv.first > cur->_kv.first)
                parent->_left = cur;
            else
                parent->_right = cur;
    
            cur->_parent = parent;
    
            while (parent && parent->_col == RED) {
    
                // 记录祖父结点
                Node *grandfather = parent->_parent;
    
                // 记录祖父结点
                if (parent == grandfather->_left) {
                    Node *uncle = grandfather->_right;
    
                    // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                    // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                    if (uncle && uncle->_col == RED) {
                        parent->_col = uncle->_col = BLACK;
                        grandfather->_col = RED;
    
                        //继续往上检查
                        cur = grandfather;
                        parent = cur->_parent;// 注意别写反了
                    } else {
                        // 情况二:叔叔不存在或者叔叔存在且为黑
    
                        //  形状一
                        //               g
                        //        p               u
                        //  cur
                        if (cur == parent->_left) {
                            // 这时候只需要右旋
                            RotateR(grandfather);
                            //只要父亲和祖父变色
                            parent->_col = BLACK;
                            grandfather->_col = RED;
                        } else {
                            //形状三
                            //               g
                            //        p               u
                            //            cur
    
                            // 这时候需要先左旋再右旋
                            // p位置左旋
                            // 再g位置右旋
                            RotateL(parent);
                            RotateR(grandfather);
    
                            //p和g位置变色
                            cur->_col = BLACK;
                            grandfather->_col = RED;
                        }
                        break; // 旋转完加变色,不需要再调整
                    }
    
                } else {
                    Node *uncle = grandfather->_left;
                    // 情况一:叔叔存在且为红 --- 当前不用旋转调整,只需要改变g、u、p的颜色
                    // 因为如果叔叔为红,那么祖父和父亲的颜色是确定的!
                    if (uncle && uncle->_col == RED) {
                        parent->_col = uncle->_col = BLACK;
                        grandfather->_col = RED;
    
                        //继续往上检查
                        cur = grandfather;
                        parent = cur->_parent;// 注意别写反了
                    } else {
                        // 情况二:叔叔不存在或者叔叔存在且为黑
    
                        //  形状二
                        //               g
                        //        u               p
                        //                              cur
                        if (cur == parent->_right) {
                            // 这时候只需要左旋
                            RotateL(grandfather);
                            //只要父亲和祖父变色
                            parent->_col = BLACK;
                            grandfather->_col = RED;
                        } else {
                            //形状四
                            //               g
                            //        u               p
                            //                   cur
    
                            // 这时候需要先右旋再左旋
                            // p位置右旋
                            // 再g位置左旋
                            RotateR(parent);
                            RotateL(grandfather);
    
                            //p和g位置变色
                            cur->_col = BLACK;
                            grandfather->_col = RED;
                        }
                        break; // 旋转完加变色,不需要再调整
                    }
                }
            }
            _root->_col = BLACK; // 根结点始终为黑
            return true;
        }
    
        void InOrder() {
            return _InOrder(_root);
        }
    
        bool IsBalance() {
            if (_root && _root->_col == RED)
                return false;
            int refBlackNum = 0; // 每条路径黑色结点的个数,这里以最右边的路径黑色结点的个数为基准
            Node *cur = _root;
            while (cur) {
                if (cur->_col == BLACK)
                    ++refBlackNum;
                cur = cur->_right;
            }
            return _Check(_root, 0, refBlackNum);
        }
    
        int Height() {
            return _Height(_root);
        }
    
        int _Height(Node *root) {
            if (root == nullptr)
                return 0;
            int lheight = _Height(root->_left);
            int rheight = _Height(root->_right);
            return lheight > rheight ? lheight + 1 : rheight + 1;
        }
    
        int Size() {
            if (!_root)
                return 0;
    
            int size = 0;
            std::stack<Node*> stack;
            Node *current = _root;
    
            while (current || !stack.empty()) {
                while (current) {
                    stack.push(current);
                    current = current->_left;
                }
    
                current = stack.top();
                stack.pop();
                size++;
                current = current->_right;
            }
    
            return size;
        }
    
    
    
        int GetRotateSize() {
            return rotateSize;
        }
    
    private:
        Node *_root = nullptr;
        int rotateSize = 0;
    
        bool _Check(Node *cur, int blackNum, int refBlackNum) {
            if (cur == nullptr) {
                if (blackNum != refBlackNum) {
                    cout << "黑结点数量不一样" << endl;
                    return false;// 到空结点开始比较黑结点是不是一样
                }
    
                return true;
            }
    
            if (cur->_col == RED && cur->_parent->_col == RED) {
                cout << "存在连续红结点:" << cur->_kv.first << endl;
                return false;
            }
    
            if (cur->_col == BLACK)
                ++blackNum; // 统计该条路径的黑结点个数
    
    
            return _Check(cur->_left, blackNum, refBlackNum) && _Check(cur->_right, blackNum, refBlackNum);
        }
    
        void _InOrder(Node *root) {
            if (root == nullptr)
                return;
            _InOrder(root->_left);
            cout << root->_kv.first << endl;
            _InOrder(root->_right);
        }
    
        void RotateL(Node *parent) {
            ++rotateSize;
    
            Node *subR = parent->_right;
            Node *subRL = subR->_left;
    
            parent->_right = subRL;
            subR->_left = parent;
            Node *ppnode = parent->_parent;
    
            if (subRL)
                subRL->_parent = parent;
            parent->_parent = subR;
    
            // 如果当前parent本身就是跟结点的话,我们得把根结点更新
            if (parent == _root) {
                _root = subR;
                subR->_parent = nullptr;
            } else {
                if (parent == ppnode->_left) {
                    // subR链接上之前的爷爷结点
                    ppnode->_left = subR;
                } else {
                    // subR链接上之前的爷爷结点
                    ppnode->_right = subR;
                }
                subR->_parent = ppnode;
            }
        }
    
        void RotateR(Node *parent) {
            ++rotateSize;
    
            Node *subL = parent->_left;
            Node *subLR = subL->_right;
    
            parent->_left = subLR;
            subL->_right = parent;
            Node *ppnode = parent->_parent;
    
            if (subLR)
                subLR->_parent = parent;
            parent->_parent = subL;
    
            // 如果当前parent本身就是跟结点的话,我们得把根结点更新
            if (parent == _root) {
                _root = subL;
                subL->_parent = nullptr;
            } else {
                if (parent == ppnode->_left) {
                    // subR链接上之前的爷爷结点
                    ppnode->_left = subL;
                } else {
                    // subR链接上之前的爷爷结点
                    ppnode->_right = subL;
                }
                subL->_parent = ppnode;
            }
        }
    };
    
  • AVLTree.h文件

    //
    // Created by 徐鹏 on 2024/3/31.
    //
    
    #ifndef DEMO_05_AVLTREE_H
    #define DEMO_05_AVLTREE_H
    
    #endif //DEMO_05_AVLTREE_H
    
    #include<iostream>
    
    using namespace std;
    
    template<class K, class V>
    struct AVLTreeNode {
        typedef AVLTreeNode<K, V> Node;
    
        Node *_left;
        Node *_right;
        Node *_parent;
    
        pair<K, V> _kv;
        int _bf; // 平衡因子
    
        AVLTreeNode(const pair<K, V> &kv) : _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0) {}
    };
    
    
    template<class K, class V>
    class AVLTree {
    public:
        typedef AVLTreeNode<K, V> Node;
    
        // AVL的查找
        Node *Find(const K &key) const {
            Node *cur = _root;
    
            // 从根节点开始搜索
            while (cur) {
                if (cur->_kv.first < key) {
                    cur = cur->_right; // 如果当前节点的键值小于目标键值,则向右子树搜索
                } else if (cur->_kv.first > key) {
                    cur = cur->_left; // 如果当前节点的键值大于目标键值,则向左子树搜索
                } else {
                    return cur; // 找到目标键值,返回当前节点
                }
            }
    
            return nullptr; // 没有找到目标键值,返回空指针
        }
    
    
        // AVL的删除
        bool Remove(const K &key) {
            return Remove(_root, key);
        }
    
        bool Remove(Node *&root, const K &key) {
            if (!root)
                return false;
    
            if (key < root->_kv.first) {
                bool res = Remove(root->_left, key);
                // 重新计算平衡因子并进行平衡调整
                if (res)
                    updateBalanceFactor(root);
                return res;
            } else if (key > root->_kv.first) {
                bool res = Remove(root->_right, key);
                // 重新计算平衡因子并进行平衡调整
                if (res)
                    updateBalanceFactor(root);
                return res;
            } else {
                if (!root->_left || !root->_right) {
                    Node *temp = root;
                    root = (root->_left) ? root->_left : root->_right;
                    if (root)
                        root->_parent = temp->_parent;
                    delete temp;
                } else {
                    Node *successor = GetSuccessor(root->_right);
                    root->_kv = successor->_kv;
                    Remove(root->_right, successor->_kv.first);
                    // 重新计算平衡因子并进行平衡调整
                    updateBalanceFactor(root);
                }
                return true;
            }
        }
    
        Node *GetSuccessor(Node *node) {
            while (node->_left)
                node = node->_left;
            return node;
        }
    
        void updateBalanceFactor(Node *node) {
            int leftHeight = (node->_left) ? _Height(node->_left) : -1;
            int rightHeight = (node->_right) ? _Height(node->_right) : -1;
            node->_bf = rightHeight - leftHeight;
        }
    
    
        // AVL的插入
        bool Insert(const pair<K, V> &kv) {
    
            if (_root == nullptr) {
                _root = new Node(kv);
                return true;
            }
    
            Node *cur = _root;
            Node *parent = nullptr;
    
            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 == nullptr
            cur = new Node(kv);
            if (parent->_kv.first < kv.first)
                parent->_right = cur;
            else if (parent->_kv.first > kv.first)
                parent->_left = cur;
    
            cur->_parent = parent;
    
            // 看当前插入的结点会不会导致树不平衡
            // parent == nullptr说明已经调整到根了
            // 平衡因子使用的是右减左的方案
            while (parent) {
                if (cur == parent->_left)
                    parent->_bf--;
                else
                    parent->_bf++;
    
                // 说明插入之前parent的平衡因子是1或者-1,现在变得非常健康,不要调整
                if (parent->_bf == 0) {
                    break;
                } else if (parent->_bf == 1 || parent->_bf == -1) {
                    // 说明插入之前parent的平衡因子是0,现在变得亚健康,需要往上看爷爷结点是不是平衡因子出现问题了
                    cur = cur->_parent;
                    parent = parent->_parent;
                } else if (parent->_bf == 2 || parent->_bf == -2) {
                    // 旋转调整
    
                    // 说明插入之前parent的平衡因子是1或者-1,现在变得不健康了,需要调整
                    if (parent->_bf == 2 && parent->_right->_bf == 1) { // parent->_bf == 2 && cur->_bf == 1
                        // 此时需要左单旋
                        RotateL(parent);
                    } else if (parent->_bf == -2 && parent->_left->_bf == -1) {
                        // 此时需要右单旋
                        RotateR(parent);
                    } else if (parent->_bf == 2 && parent->_right->_bf == -1) {
                        // 此时需要右旋再左旋
                        RotateRL(parent);
                    } else {
                        // 此时需要左旋再右旋
                        RotateLR(parent);
                    }
                    break;// 调整结束,不用再往上调整
                }
            }
            return true;
        }
    
        void RotateL(Node *parent) {
            ++rotateSize;
    
            Node *subR = parent->_right;
            Node *subRL = subR->_left;
    
            parent->_right = subRL;
            subR->_left = parent;
            Node *ppnode = parent->_parent;
    
            if (subRL)
                subRL->_parent = parent;
            parent->_parent = subR;
    
    
    
            // 如果当前parent本身就是跟结点的话,我们得把根结点更新
            if (parent == _root) {
                _root = subR;
                subR->_parent = nullptr;
            } else {
                if (parent == ppnode->_left) {
                    // subR链接上之前的爷爷结点
                    ppnode->_left = subR;
                } else {
                    // subR链接上之前的爷爷结点
                    ppnode->_right = subR;
                }
                subR->_parent = ppnode;
            }
            parent->_bf = 0;
            subR->_bf = 0;
        }
    
        void RotateR(Node *parent) {
            ++rotateSize;
    
            Node *subL = parent->_left;
            Node *subLR = subL->_right;
    
            parent->_left = subLR;
            subL->_right = parent;
            Node *ppnode = parent->_parent;
    
            if (subLR)
                subLR->_parent = parent;
            parent->_parent = subL;
    
    
    
            // 如果当前parent本身就是跟结点的话,我们得把根结点更新
            if (parent == _root) {
                _root = subL;
                subL->_parent = nullptr;
            } else {
                if (parent == ppnode->_left) {
                    // subR链接上之前的爷爷结点
                    ppnode->_left = subL;
                } else {
                    // subR链接上之前的爷爷结点
                    ppnode->_right = subL;
                }
                subL->_parent = ppnode;
            }
            parent->_bf = 0;
            subL->_bf = 0;
        }
    
        void RotateRL(Node *parent) {
            // 因为左单旋转和右单旋后bf都设置为0了,因此我们需要手动再设置改变的结点的平衡因子
    
            // 会改变平衡因子的结点
            Node *subR = parent->_right;
            Node *subRL = subR->_left;
    
            //  用来记录没旋转前subRL的结点的bf
            int rlbf = subRL->_bf;
    
            RotateR(parent->_right);
            RotateL(parent);
    
            // 讨论旋转后的bf(平衡因子改变的结点)
            if (rlbf == -1) {
                subRL->_bf = 0;
                subR->_bf = 1;
                parent->_bf = 0;
            } else if (rlbf == 1) {
                subRL->_bf = 0;
                subR->_bf = 0;
                parent->_bf = -1;
            } else if (rlbf == 0) { // rlbf == 0
                subRL->_bf = 0;
                subR->_bf = 0;
                parent->_bf = 0;
            } else {
                assert(false);
            }
        }
    
        void RotateLR(Node *parent) {
            // 因为左单旋转和右单旋后bf都设置为0了,因此我们需要手动再设置改变的结点的平衡因子
    
            // 会改变平衡因子的结点
            Node *subL = parent->_left;
            Node *subLR = subL->_right;
    
            //  用来记录没旋转前subLR的结点的bf
            int lrbf = subLR->_bf;
    
            RotateL(parent->_left);
            RotateR(parent);
    
            // 讨论旋转后的bf(平衡因子改变的结点)
            if (lrbf == -1) {
                subLR->_bf = 0;
                subL->_bf = 0;
                parent->_bf = 1;
            } else if (lrbf == 1) {
                subLR->_bf = 0;
                subL->_bf = -1;
                parent->_bf = 0;
            } else if (lrbf == 0) { // lrbf == 0
                subLR->_bf = 0;
                subL->_bf = 0;
                parent->_bf = 0;
            } else {
                assert(false);
            }
    
        }
    
    
        void InOrder() {
            _InOrder(_root);
        }
    
        int Height() {
            return _Height(_root);
        }
    
        bool IsBalance() {
            return _IsBalance(_root);
        }
    
        int Size() {
            if (!_root)
                return 0;
    
            int size = 0;
            std::stack<Node*> stack;
            Node *current = _root;
    
            while (current || !stack.empty()) {
                while (current) {
                    stack.push(current);
                    current = current->_left;
                }
    
                current = stack.top();
                stack.pop();
                size++;
                current = current->_right;
            }
    
            return size;
        }
    
    
        int GetRotateSize() {
            return rotateSize;
        }
    
    
    private:
    
        bool _IsBalance(Node *root) {
            if (root == nullptr)
                return true;
            int lheight = _Height(root->_left);
            int rheight = _Height(root->_right);
            if (root->_bf != (rheight - lheight) || root->_bf > 1 || root->_bf < -1)
                return false;
            return _IsBalance(root->_left) && _IsBalance(root->_right);
        }
    
        int _Height(Node *root) {
            if (root == nullptr)
                return 0;
            int lheight = _Height(root->_left);
            int rheight = _Height(root->_right);
            return lheight > rheight ? lheight + 1 : rheight + 1;
        }
    
        void _InOrder(Node *root) {
            if (root == nullptr)
                return;
            _InOrder(root->_left);
            cout << root->_kv.first << ":" << root->_kv.second << "[" << root->_bf << "]" << endl;
            _InOrder(root->_right);
    
        }
    
    
        Node *_root = nullptr;
        int rotateSize = 0;
    };
    
  • BinarySeachTree.h文件

    //
    // Created by 徐鹏 on 2024/3/31.
    //
    
    #ifndef DEMO_05_BINARYSEACHTREE_H
    #define DEMO_05_BINARYSEACHTREE_H
    
    #endif //DEMO_05_BINARYSEACHTREE_H
    
    #include <iostream>
    
    using namespace std;
    
    template<class K>
    struct BSTreeNode {
        //typedef BSTreeNode<K> Node;
    
        BSTreeNode<K> *_left;
        BSTreeNode<K> *_right;
        K _key;
    
        BSTreeNode(const K &key) : _left(nullptr), _right(nullptr), _key(key) {}
    
    };
    
    
    template<class K>
    class BinarySearchTree {
    public:
        typedef BSTreeNode<K> Node;
    
        BinarySearchTree() = default;
    
        BinarySearchTree(const BinarySearchTree<K> &b) {
            _root = Copy(b._root);
        }
    
        Node *Copy(Node *root) {
            if (root == nullptr)
                return nullptr;
            Node *newNode = new Node(root->_key);
            newNode->_left = Copy(root->_left);
            newNode->_right = Copy(root->_right);
    
            return newNode;
    
        }
    
        BinarySearchTree<K> &operator=(BinarySearchTree<K> b) {
            swap(b._root, _root);
            return *this;
        }
    
        ~BinarySearchTree() {
            Destroy(_root);
        }
    
        void Destroy(Node *root) {
            if (root == nullptr)
                return;
            Destroy(root->_left);
            Destroy(root->_right);
            delete root;
        }
    
    
        bool Erase(const K &key) {
            Node *cur = _root;
            Node *parent = nullptr;
    
            if (cur == nullptr)
                return false;
    
    
            while (cur) {
                if (cur->_key < key) {
                    parent = cur;
                    cur = cur->_right;
                } else if (cur->_key > key) {
                    parent = cur;
                    cur = cur->_left;
                } else {
                    //找到要删的结点
    
                    // 当前要删的结点有一个孩子或者没有孩子
                    if (cur->_left == nullptr) {
                        // 判断跟结点是否只有一颗子树
                        if (cur == _root) {
                            _root = _root->_right;
                        } else {
                            if (parent->_left == cur)
                                parent->_left = cur->_right;
                            else
                                parent->_right = cur->_right;
                        }
    
                        delete cur;
                        return true;
    
                    } else if (cur->_right == nullptr) {
    
                        // 判断跟结点是否只有一颗子树
                        if (cur == _root) {
                            _root = _root->_left;
                        } else {
                            if (parent->_left == cur)
                                parent->_left = cur->_left;
                            else
                                parent->_right = cur->_left;
                        }
    
    
                        delete cur;
                        return true;
    
                    } else {
                        // 当前要删的结点有两个孩子
    
                        // 找个替代的值去删  -- 找左子树的最右结点,即左子树最大的结点
    
                        Node *LeftMax = cur->_left;
                        Node *LeftMaxParent = cur;
                        while (LeftMax->_right) {
                            LeftMaxParent = LeftMax;
                            LeftMax = LeftMax->_right;
                        }
    
                        cur->_key = LeftMax->_key;
                        if (LeftMaxParent->_left == LeftMax)
                            LeftMaxParent->_left = LeftMax->_left;
                        else
                            LeftMaxParent->_right = LeftMax->_left;
                        delete LeftMax;
                        return true;
                    }
                }
            }
            return false;
        }
    
        bool Insert(const K &key) {
            Node *cur = _root;
            Node *parent = nullptr;
            if (cur == nullptr) {
                Node *newNode = new Node(key);
                _root = newNode;
                return true;
            }
            while (cur) {
                if (cur->_key < key) {
                    parent = cur;
                    cur = cur->_right;
                } else if (cur->_key > key) {
                    parent = cur;
                    cur = cur->_left;
                } else {
                    return false;
                }
            }
    
            // cur == nullptr
    //        Node *newNode = new Node(key);
    //        if (parent->_key < key)
    //            parent->_right = newNode;
    //        else if (parent->_key > key)
    //            parent->_left = newNode;
    
            cur = new Node(key);
            if (parent->_key < key)
                parent->_right = cur;
            else if (parent->_key > key)
                parent->_left = cur;
            return true;
        }
    
        bool Find(const K &key) {
            Node *cur = _root;
            if (cur == nullptr)
                return false;
    
            while (cur) {
                if (cur->_key < key) {
                    cur = cur->_right;
                } else if (cur->_key > key) {
                    cur = cur->_left;
                } else {
                    return true;
                }
            }
    
            return false;
        }
    
        int Height() {
            return _Height(_root);
        }
    
        int _Height(Node *root) {
            if (root == nullptr)
                return 0;
            int lheight = _Height(root->_left);
            int rheight = _Height(root->_right);
            return lheight > rheight ? lheight + 1 : rheight + 1;
        }
    
        int Size() {
            if (!_root)
                return 0;
    
            int size = 0;
            std::stack<Node *> stack;
            Node *current = _root;
    
            while (current || !stack.empty()) {
                while (current) {
                    stack.push(current);
                    current = current->_left;
                }
    
                current = stack.top();
                stack.pop();
                size++;
                current = current->_right;
            }
    
            return size;
        }
    
        void InOrder() {
            _InOrder(_root);
            cout << endl;
        }
    
    
        bool FindR(const K &key) {
            return _FindR(_root, key);
        }
    
        bool InsertR(const K &key) {
            return _InsertR(_root, key);
        }
    
        bool EraseR(const K &key) {
            return _EraseR(_root, key);
        }
    
    
    private:
    
        bool _EraseR(Node *root, const K &key) {
            if (root == nullptr)
                return false;
    
            if (root->_key < key) {
                return _EraseR(root->_right, key);
            } else if (root->_key > key) {
                return _EraseR(root->_left, key);
            } else {
    
                Node *del = root;
                if (root->_right == nullptr)
                    root = root->_left;
                else if (root->_left == nullptr)
                    root = root->_right;
                else {
                    // 将当前要删的结点的值和当前结点的左子树最大值的结点交换
                    Node *LeftMax = root->_left;
                    while (LeftMax->_right) {
                        LeftMax = LeftMax->_right;
                    }
    
                    swap(LeftMax->_key, root->_key);
    
                    return _EraseR(root, key);
                }
                delete del;
                return true;
            }
        }
    
        bool _InsertR(Node *&root, const K &key) {
            if (root == nullptr) {
                root = new Node(key);
                return true;
            }
    
            if (root->_key < key) {
                return _InsertR(root->_right, key);
            } else if (root->_key > key) {
                return _InsertR(root->_left, key);
            } else {
                return false;
            }
        }
    
        bool _FindR(Node *root, const K &key) {
            if (root == nullptr)
                return false;
    
            if (root->_key < key) {
                return _FindR(root->_right, key);
            } else if (root->_key > key) {
                return _FindR(root->_left, key);
            } else {
                return true;
            }
        }
    
    
        void _InOrder(Node *root) {
            if (root == nullptr)
                return;
            if (root->_left)
                _InOrder(root->_left);
            cout << root->_key << " ";
            if (root->_right)
                _InOrder(root->_right);
        }
    
        Node *_root = nullptr;
    };
    
    
    namespace kv {
        template<class K, class V>
        struct BSTreeNode {
            //typedef BSTreeNode<K> Node;
    
            BSTreeNode<K, V> *_left;
            BSTreeNode<K, V> *_right;
            K _key;
            V _val;
    
            BSTreeNode(const K &key, const K &val) : _left(nullptr), _right(nullptr), _key(key), _val(val) {}
    
        };
    
    
        template<class K, class V>
        class BinarySearchTree {
        public:
            typedef BSTreeNode<K, V> Node;
    
            BinarySearchTree() = default;
    
            BinarySearchTree(const BinarySearchTree<K, V> &b) {
                _root = Copy(b._root);
            }
    
            Node *Copy(Node *root) {
                if (root == nullptr)
                    return nullptr;
                Node *newNode = new Node(root->_key);
                newNode->_left = Copy(root->_left);
                newNode->_right = Copy(root->_right);
    
                return newNode;
    
            }
    
            BinarySearchTree<K, V> &operator=(BinarySearchTree<K, V> b) {
                swap(b._root, _root);
                return *this;
            }
    
            ~BinarySearchTree() {
                Destroy(_root);
            }
    
            void Destroy(Node *root) {
                if (root == nullptr)
                    return;
                Destroy(root->_left);
                Destroy(root->_right);
                delete root;
            }
    
    
            bool Erase(const K &key) {
                Node *cur = _root;
                Node *parent = nullptr;
    
                if (cur == nullptr)
                    return false;
    
    
                while (cur) {
                    if (cur->_key < key) {
                        parent = cur;
                        cur = cur->_right;
                    } else if (cur->_key > key) {
                        parent = cur;
                        cur = cur->_left;
                    } else {
                        //找到要删的结点
    
                        // 当前要删的结点有一个孩子或者没有孩子
                        if (cur->_left == nullptr) {
                            // 判断跟结点是否只有一颗子树
                            if (cur == _root) {
                                _root = _root->_right;
                            } else {
                                if (parent->_left == cur)
                                    parent->_left = cur->_right;
                                else
                                    parent->_right = cur->_right;
                            }
    
                            delete cur;
                            return true;
    
                        } else if (cur->_right == nullptr) {
    
                            // 判断跟结点是否只有一颗子树
                            if (cur == _root) {
                                _root = _root->_left;
                            } else {
                                if (parent->_left == cur)
                                    parent->_left = cur->_left;
                                else
                                    parent->_right = cur->_left;
                            }
    
    
                            delete cur;
                            return true;
    
                        } else {
                            // 当前要删的结点有两个孩子
    
                            // 找个替代的值去删  -- 找左子树的最右结点,即左子树最大的结点
    
                            Node *LeftMax = cur->_left;
                            Node *LeftMaxParent = cur;
                            while (LeftMax->_right) {
                                LeftMaxParent = LeftMax;
                                LeftMax = LeftMax->_right;
                            }
    
                            cur->_key = LeftMax->_key;
                            if (LeftMaxParent->_left == LeftMax)
                                LeftMaxParent->_left = LeftMax->_left;
                            else
                                LeftMaxParent->_right = LeftMax->_left;
                            delete LeftMax;
                            return true;
                        }
                    }
                }
                return false;
            }
    
            bool Insert(const K &key, const K &val) {
                Node *cur = _root;
                Node *parent = nullptr;
                if (cur == nullptr) {
                    Node *newNode = new Node(key, val);
                    _root = newNode;
                    return true;
                }
                while (cur) {
                    if (cur->_key < key) {
                        parent = cur;
                        cur = cur->_right;
                    } else if (cur->_key > key) {
                        parent = cur;
                        cur = cur->_left;
                    } else {
                        return false;
                    }
                }
    
                // cur == nullptr
                Node *newNode = new Node(key, val);
                if (parent->_key < key)
                    parent->_right = newNode;
                else if (parent->_key > key)
                    parent->_left = newNode;
                return true;
            }
    
            Node *Find(const K &key) {
                Node *cur = _root;
                if (cur == nullptr)
                    return nullptr;
    
                while (cur) {
                    if (cur->_key < key) {
                        cur = cur->_right;
                    } else if (cur->_key > key) {
                        cur = cur->_left;
                    } else {
                        return cur;
                    }
                }
    
                return nullptr;
            }
    
            void InOrder() {
                _InOrder(_root);
                cout << endl;
            }
    
    
        private:
    
            void _InOrder(Node *root) {
                if (root == nullptr)
                    return;
                if (root->_left)
                    _InOrder(root->_left);
                cout << root->_key << " ";
                if (root->_right)
                    _InOrder(root->_right);
            }
    
            Node *_root = nullptr;
        };
    
    }
    
  • main.cpp文件

    #include<stack>
    #include"AVLTree.h"
    #include"RBTree.h"
    #include"BinarySeachTree.h"
    #include<vector>
    
    // 插入结点的个数 , 可自行修改查看
    #define N 2000 
    
    void test_ARB1() {
        vector<int> v;
        v.reserve(N);
        srand(time(0));
    
        for (size_t i = 0; i < N; i++) {
            v.push_back(rand() + i); // 让几棵树插入随机值
            //v.push_back( i );// 让几棵树插入有序值 -- 这个会导致二叉搜索树和结点个数一样高
        }
    
        RBTree<int, int> rbt;
        AVLTree<int, int> avl;
        BinarySearchTree<int> bst;
    
        int begin1 = clock();
        for (auto &e: v) {
            rbt.Insert(make_pair(e, e));
        }
        int end1 = clock();
    
        int begin2 = clock();
        for (auto &e: v) {
            avl.Insert(make_pair(e, e));
        }
        int end2 = clock();
    
        int begin3 = clock();
        for (auto &e: v) {
            bst.Insert(e);
        }
        int end3 = clock();
    
        cout << "RBTree RotateSize:" << rbt.GetRotateSize() << endl;
        cout << "AVLTree RotateSize:" << avl.GetRotateSize() << endl;
        cout << "============================" << endl;
    
    
        cout << "RBTree Insert:" << end1 - begin1 << endl;
        cout << "AVLTree Insert:" << end2 - begin2 << endl;
        cout << "BinarySearchTree Insert:" << end3 - begin3 << endl;
        cout << "============================" << endl;
    
    
        cout << "RBTree IsBalance:" << rbt.IsBalance() << endl;
        cout << "AVLTree IsBalance:" << avl.IsBalance() << endl;
        cout << "============================" << endl;
    
    
        cout << "RBTree Height:" << rbt.Height() << endl;
        cout << "RBTree Size:" << rbt.Size() << endl;
        cout << "============================" << endl;
    
    
        cout << "AVLTree Height:" << avl.Height() << endl;
        cout << "AVLTree Size:" << avl.Size() << endl;
        cout << "============================" << endl;
    
    
        cout << "BinarySearchTree Height:" << bst.Height() << endl;
        cout << "BinarySearchTree Size:" << bst.Size() << endl;
        cout << "============================" << endl;
    
    
        int begin4 = clock();
        for (auto &e: v) {
            rbt.Find(e);
        }
    
    //    // 随机值
    //    for (size_t i = 0; i < N; i++) {
    //        rbt.Find((rand() + i));
    //    }
    
        int end4 = clock();
    
        int begin5 = clock();
        for (auto &e: v) {
            avl.Find(e);
        }
    
    //    // 随机值
    //    for (size_t i = 0; i < N; i++) {
    //        avl.Find((rand() + i));
    //    }
        int end5 = clock();
    
    
        int begin6 = clock();
        for (auto &e: v) {
            bst.Find(e);
        }
    
    //    // 随机值
    //    for (size_t i = 0; i < N; i++) {
    //        avl.Find((rand() + i));
    //    }
        int end6 = clock();
        cout << "RBTree Find:" << end4 - begin4 << endl;
        cout << "AVLTree Find:" << end5 - begin5 << endl;
        cout << "BinarySearchTree Find:" << end6 - begin6 << endl;
    
    }
    
    int main() {
        test_ARB1();
        return 0;
    }
    

当插入的是有序值时,输出为以下(此时N为2000)

RBTree RotateSize:1981
AVLTree RotateSize:1989
============================
RBTree Insert:148
AVLTree Insert:132
BinarySearchTree Insert:2548
============================
RBTree IsBalance:1
AVLTree IsBalance:1
============================
RBTree Height:19
RBTree Size:2000
============================
AVLTree Height:11
AVLTree Size:2000
============================
BinarySearchTree Height:2000
BinarySearchTree Size:2000
============================
RBTree Find:76
AVLTree Find:79
BinarySearchTree Find:2525

可以看到二叉搜索树的高度非常高,而红黑树和AVL树高度不高。也能看到旋转次数红黑树比AVL树少。

我们再来看插入的是随机值,输出为以下(此时N为2000):

RBTree RotateSize:1191
AVLTree RotateSize:1454
============================
RBTree Insert:220
AVLTree Insert:347
BinarySearchTree Insert:165
============================
RBTree IsBalance:1
AVLTree IsBalance:1
============================
RBTree Height:14
RBTree Size:2000
============================
AVLTree Height:13
AVLTree Size:2000
============================
BinarySearchTree Height:29
BinarySearchTree Size:2000
============================
RBTree Find:128
AVLTree Find:129
BinarySearchTree Find:127

可以看到二叉搜索树的高度依然最高,红黑树其次,AVL树最低。也能看到旋转次数红黑树依然比AVL树少。

当N非常大的时候,二叉搜索树与红黑树、AVL树不是一个量级的,不用比较。

我们可以单独比较红黑树、AVL树。

  • main.cpp文件

    #include<stack>
    #include"AVLTree.h"
    #include"RBTree.h"
    #include"BinarySeachTree.h"
    #include<vector>
    
    #define N 3000000
    
    void test_ARB2() {
        vector<int> v;
        v.reserve(N);
        srand(time(0));
    
        for (size_t i = 0; i < N; i++) {
            v.push_back(rand() + i); // 让几棵树插入随机值
    //        v.push_back( i );// 让几棵树插入有序值 -- 这个会导致二叉搜索树和结点个数一样高
        }
    
        RBTree<int, int> rbt;
        AVLTree<int, int> avl;
    
        int begin1 = clock();
        for (auto &e: v) {
            rbt.Insert(make_pair(e, e));
        }
        int end1 = clock();
    
        int begin2 = clock();
        for (auto &e: v) {
            avl.Insert(make_pair(e, e));
        }
        int end2 = clock();
    
    
        cout << "RBTree RotateSize:" << rbt.GetRotateSize() << endl;
        cout << "AVLTree RotateSize:" << avl.GetRotateSize() << endl;
        cout << "============================" << endl;
    
    
        cout << "RBTree Insert:" << end1 - begin1 << endl;
        cout << "AVLTree Insert:" << end2 - begin2 << endl;
        cout << "============================" << endl;
    
    
        cout << "RBTree IsBalance:" << rbt.IsBalance() << endl;
        cout << "AVLTree IsBalance:" << avl.IsBalance() << endl;
        cout << "============================" << endl;
    
    
        cout << "RBTree Height:" << rbt.Height() << endl;
        cout << "RBTree Size:" << rbt.Size() << endl;
        cout << "============================" << endl;
    
    
        cout << "AVLTree Height:" << avl.Height() << endl;
        cout << "AVLTree Size:" << avl.Size() << endl;
        cout << "============================" << endl;
    
    
    
        int begin4 = clock();
        for (auto &e: v) {
            rbt.Find(e);
        }
    
    //    // 随机值
    //    for (size_t i = 0; i < N; i++) {
    //        rbt.Find((rand() + i));
    //    }
    
        int end4 = clock();
    
        int begin5 = clock();
        for (auto &e: v) {
            avl.Find(e);
        }
    
    //    // 随机值
    //    for (size_t i = 0; i < N; i++) {
    //        avl.Find((rand() + i));
    //    }
        int end5 = clock();
    
    
        cout << "RBTree Find:" << end4 - begin4 << endl;
        cout << "AVLTree Find:" << end5 - begin5 << endl;
    
    }
    int main() {
    //    test_ARB1();
        test_ARB2();
        return 0;
    }
    

当插入的是随机值,输出为以下(此时N为3000000):

RBTree RotateSize:1745356
AVLTree RotateSize:2092687
============================
RBTree Insert:2483973
AVLTree Insert:2235168
============================
RBTree IsBalance:1
AVLTree IsBalance:1
============================
RBTree Height:27
RBTree Size:2997882
============================
AVLTree Height:25
AVLTree Size:2997882
============================
RBTree Find:1548347
AVLTree Find:1466679

可以看到红黑树比AVL树要高,红黑树的旋转次数比AVL树要少35万次左右,查找的时间差不多。

现实中,其实红黑树和AVL树的性能是差不多的,但是大家一般用的都是红黑树,比如set和map的底层就是由红黑树实现的。


OKOK,红黑树就到这里。如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。

Xpccccc的github主页

  • 25
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Xpccccc

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

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

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

打赏作者

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

抵扣说明:

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

余额充值