数据结构——红黑树

1.红黑树是什么?

红黑树首先是一棵自平衡二叉查找树。它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL 。
它具有以下的特性:

  • 节点颜色非红即黑
  • 根节点黑色
  • 叶子节点黑色(空节点)
  • 红色节点不能连续
  • 节点到空节点的任意路径黑色节点个数相同

2.原理

2.1、左旋和右旋

如下图所示,设失衡节点为S,父节点为P,父节点为G,P兄弟节点为B。
1)满足特性(4),将P涂黑;此时左侧黑色长度加一。
2)满足特性(5),将G涂红;此时右侧黑色长度减一。
3)满足特性(5),以P为中心向右旋转;;此时红黑树平衡。

在这里插入图片描述

2.1、添加节点

首先,按照二叉树的原理,插入新节点。
设失衡节点为S,父节点为P,祖父节点为G,P兄弟节点为B。
则插入的基本流程如下:
1)判断是否根节点
2)判断父节点颜色
3)判断父节点属于祖父节点的哪一个分支
4)判断失衡节点属于祖父节点的哪一个分支
在这里插入图片描述

2.2、删除节点

首先,按照二叉树的原理,删除指定节点S。
设失衡节点为S(S = P->L),父节点为P,兄弟节点为B。
则插入的基本流程如下:
1)判断是否存在左节点
2)判断是否存在右节点
3)判断节点颜色
4)判断兄弟节点的右节点颜色
5)判断兄弟节点的左节点颜色
6)判断父节点颜色
在这里插入图片描述

3.示例

简单实现

enum RBColor { RED, BLACK };

template <class K, class V>
class RBTree {
 private:
  class RBNode {
   private:
    friend class RBTree;
    K key;
    V val;
    RBColor color;
    RBNode *l;
    RBNode *r;
    RBNode *p;

   public:
    RBNode(RBNode *parent, K key, V data) : p(parent), key(key), val(data) {
      this->l = this->r = nullptr;
      if (this->p == nullptr)
        this->color = BLACK;  // 2)
      else
        this->color = RED;  // 5)
    }
    ~RBNode() { ; }
  };

  void DelNode(RBNode *node) {
    if (node != nullptr) {
      DelNode(node->l);
      DelNode(node->r);
      delete node;
    }
  }

  bool isRed(RBNode *node) {
    if (node == nullptr) return false;
    if (node->color == RED)
      return true;
    else
      return false;
  }

  RBNode *ReColor(RBNode *node) {
    if (node != root) node->color = RED;
    node->l->color = node->r->color = BLACK;
    return node;
  }

  RBNode *ReColor(RBNode *node, bool left) {
    node->color = RED;
    if (left)
      node->l->color = BLACK;
    else
      node->r->color = BLACK;
    return node;
  }

  RBNode *LL(RBNode *node) {
    RBNode *_new = node->l;
    // 更新子节点信息
    node->l = _new->r;
    if (node->l != nullptr) node->l->p = node;
    _new->r = node;
    // 更新父节点信息
    _new->p = node->p;
    node->p = _new;
    return _new;
  }

  RBNode *RR(RBNode *node) {
    RBNode *_new = node->r;
    node->r = _new->l;
    if (node->r != nullptr) node->r->p = node;
    _new->l = node;
    _new->p = node->p;
    node->p = _new;
    return _new;
  }

  /*
   * 红黑树插入存在3种情形:(1,2不需要特殊处理)
   * 1) 插入根节点
   * 2) 父节点黑色
   * 3) 父节点/叔叔红色, 祖父节点黑色
   *    3)递归后, 出现以下情形:
   *    3-1) 父节点黑色, 同2)
   *    3-2) 父节点/叔叔红色, 祖父节点黑色, 同3)
   *    3-3) 父节点红色, 叔叔节点/祖父节点黑色
   */
  RBNode *add(RBNode *parent, RBNode *node, K key, V data, int &weight) {
    if (node == nullptr) {
      weight = 3;
      return new RBNode(parent, key, data);
    }
    if (key < node->key) {
      node->l = add(node, node->l, key, data, weight);
      if (weight) {
        weight = (weight == 3) ? -3 : weight;
        weight = weight - 1;
      }
    } else if (key > node->key) {
      node->r = add(node, node->r, key, data, weight);
      weight = (weight == 0) ? weight : weight + 1;
    }

    return rebalance(node, weight);
  }

  RBNode *get(RBNode *node, K key) {
    if (node == nullptr) return nullptr;
    if (node->key == key)
      return node;
    else if (key < node->key)
      return get(node->l, key);
    else
      return get(node->r, key);
  }

  RBNode *Max(RBNode *node) {
    while (node->r != nullptr) {
      node = node->r;
    }
    return node;
  }

  RBNode *rebalance(RBNode *node, int &weight) {
    switch (weight) {
      case -5:  // 此时左子树红色长度加1
      case 3:
        if ((node->l->l != nullptr && isRed(node->l->l)) ||
            (node->l->r != nullptr && isRed(node->l->r))) {
          if (isRed(node->l)) {
            if (isRed(node->r))  // 插入情形3-2)
            {
              node = ReColor(node);
              weight = 3;
              break;
            } else {                                   // 插入情形3-3)
              if (weight == 3) node->l = RR(node->l);  // 转换为ll情形
              node = ReColor(node, true);              // 解决特性4)
              node = LL(node);                         // 解决特性5)
            }
          }
        }
        weight = 0;
        break;
      case 5:  // 此时右子树红色长度加1
      case -3:
        if ((node->r->r != nullptr && isRed(node->r->r)) ||
            (node->r->l != nullptr && isRed(node->r->l))) {
          if (isRed(node->r)) {
            if (isRed(node->l))  // 情形3-2)
            {
              node = ReColor(node);
              weight = 3;
              break;
            } else {                                    // 情形3-3)
              if (weight == -3) node->r = LL(node->r);  // 转换为rr情形
              node = ReColor(node, false);              // 解决特性4)
              node = RR(node);                          // 解决特性5)
            }
          }
        }
        weight = 0;
        break;
      // 此时左子树黑色长度减1
      case -2:
        /*
         * 设当前节点的左右子树的黑色节点长度L=R=n
         * 此时,左子树L=n-1,R=n
         * 为使左右平衡,存在2个方案:
         *  1)通过旋转将右子黑色节点转移到左子树,同时将一个红色节点涂黑。
         *  2)将右子树的一个黑色节点涂红,向上递归。
         */
        if (node->r->r != nullptr && isRed(node->r->r)) {  // 方案1)
          node = RR(node);
          // 交换父节点和右节点颜色
          node->color = node->l->color;
          node->l->color = BLACK;
          // 涂黑红色颜色
          node->r->color = BLACK;
          // 平衡常数置零
          weight = 0;
        } else if (node->r->l != nullptr && isRed(node->r->l)) {  // 方案1)
          node->r = LL(node->r);
          node = RR(node);
          // 交换父节点和右节点颜色
          node->color = node->l->color;
          node->l->color = BLACK;
          // 涂黑红色颜色
          node->r->color = BLACK;
          // 平衡常数置零
          weight = 0;
        } else if (isRed(node->r)) {
          node = RR(node);
          // 交换父节点和右节点颜色
          node->color = BLACK;
          node->l->color = RED;
          node->l = rebalance(node->l, weight);
        } else if (isRed(node->r) == false) {  // 右节点和右子节点均为黑色
          node->r->color = RED;
          if (isRed(node)) {  // 父节点红色
            node->color = BLACK;
            weight = 0;
          } else {  // 父节点黑色 方案2)
            weight = -1;
          }
        }
        break;
      case 2:  // 右子树黑色长度减1
        if (node->l->l != nullptr && isRed(node->l->l)) {  // 方案1)
          node = LL(node);
          // 交换父节点和右节点颜色
          node->color = node->r->color;
          node->r->color = BLACK;
          // 涂黑红色颜色
          node->l->color = BLACK;
          // 平衡常数置零
          weight = 0;
        } else if (node->l->r != nullptr && isRed(node->l->r)) {  // 方案1)
          node->l = RR(node->l);
          node = LL(node);
          // 交换父节点和右节点颜色
          node->color = node->r->color;
          node->r->color = BLACK;
          // 涂黑红色颜色
          node->l->color = BLACK;
          // 平衡常数置零
          weight = 0;
        } else if (isRed(node->l)) {
          node = LL(node);
          // 交换父节点和右节点颜色
          node->color = BLACK;
          node->r->color = RED;
          node->r = rebalance(node->r, weight);
        } else if (isRed(node->l) == false) {  // 节点和子节点均为黑色
          node->l->color = RED;
          if (isRed(node)) {  // 父节点红色
            node->color = BLACK;
            weight = 0;
          } else {  // 父节点黑色 方案2)
            weight = -1;
          }
        }
        break;
      default:
        break;
    }
    return node;
  }

  /*
   * 红黑树插入存在4种情形:
   * 1) 叶子节点
   * 2) 存在左子树
   *    2-1) 删除节点红-子节点黑, 不符合特性5)
   *    2-2) 删除节点黑-子节点红
   * 3) 存在右子树
   *    3-1) 删除节点红-子节点黑, 不符合特性5)
   *    3-2) 删除节点黑-子节点红
   * 4)存在左右子树, 用前驱节点(K,V)替换删除节点,转变为删除前驱节点。1) 2)
   */
  RBNode *remove(RBNode *node, K key, int &weight) {
    if (node == nullptr) return nullptr;

    RBNode *_new = nullptr;
    if (key < node->key) {
      node->l = remove(node->l, key, weight);
      _new = node;
      weight = (weight == -1) ? -2 : 0;  //
    } else if (key > node->key) {
      node->r = remove(node->r, key, weight);
      weight = (weight == -1) ? 2 : 0;  //
      _new = node;
    } else {
      if (node->l == nullptr) {
        _new = node->r;
        if (_new != nullptr) {  // 3-2)
          _new->p = node->p;
          _new->color = BLACK;
        } else if (node->color == BLACK) {
          weight = -1;  // 1) 删除节点为黑
        } else {
          ;  // 1) 当前节点为红
        }
      } else if (node->r == nullptr) {
        _new = node->l;  // 2-2)
        _new->p = node->p;
        _new->color = BLACK;
      } else {  // 4)
        _new = Max(node->l);  // 在左子树寻找前驱节点
        _new->l = remove(node->l, _new->key, weight);
        _new->p = node->p;
        _new->r = node->r;
        _new->color = node->color;
        if(_new->l != nullptr)
          _new->l->p = _new;
        if(_new->r != nullptr)
          _new->r->p = _new;
        weight = (weight == -1) ? -2 : 0;
      }
    }

    return rebalance(_new, weight);
  }

  RBNode *root;

#ifdef _DEBUG
  int Check(RBNode *node) {
    if (node == nullptr)
      return 1;
    else {
      if (isRed(node) && isRed(node->p)) return -1;
      if (node->l != nullptr && node != node->l->p) return -1;
      if (node->r != nullptr && node != node->r->p) return -1;
      int left = Check(node->l);
      int right = Check(node->r);
      if (left == -1 || right == -1 || left != right) return -1;
      if (node->color == RED)
        return left;
      else
        return left + 1;
    }
  }
#endif

 public:
  RBTree() { root = nullptr; }

  ~RBTree() { DelNode(root); }

  void add(K key, V data) {
    RBNode *node = get(root, key);
    if (node != nullptr) return;
    int weight = 0;
    root = add(root, root, key, data, weight);
  }

  V get(int key) {
    RBNode *node = get(root, key);
    if (node != nullptr) return node->val;
    return nullptr;
  }

#ifdef _DEBUG
  int Check() { return Check(root); }
#endif

  V remove(int key) {
    RBNode *node = get(root, key);
    if (node == nullptr) return 0;
    V val = node->val;
    int weight = 0;
    root = remove(root, key, weight);
    delete node;
    return val;
  }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值