C++进阶--红黑树

简介: C++进阶--红黑树

概念与特性

红黑树,是一种自平衡的二叉搜索树,它具有以下特点:

  1. 每个节点要么是红色,要么是黑色
  2. 根节点是黑色的。
  3. 每个叶子节点(NIL节点,空节点)都是黑色的。
  4. 如果一个节点是红色的,那么它的两个子节点都是黑色的,也就说,不存在两个连续的红色节点。
  5. 对于任意节点,从该节点到其后代叶子节点的所有路径上包含相同数目的黑色节点,即保证了红黑树的黑色节点高度相同。

红黑树的定义

enum Colour
{
  RED,
  BLACK
};
template<class K,class V>
struct RBTreeNode
{
  RBTreeNode<K, V>* _left;
  RBTreeNode<K, V>* _right;
  RBTreeNode<K, V>* _parent;
  pair<K, V> _kv;
  Colour _col;
  RBTreeNode(const pair<K, V>& kv)
    :_left(nullptr)
    , _right(nullptr)
    , _parent(nullptr)
    , _kv(kv)
    , _col(RED)
  {
  }
};

红黑树的插入操作

旋转的见:AVL树链接入口

bool Insert(const pair<K, V>& kv)
  {
    if (_root == nullptr)
    {
      _root = new Node(kv);
      _root->_col = BLACK;
      return true;
    }
    //确定插入位置
    Node* parent = nullptr;
    Node* cur = _root;
    while (cur)
    {
      if (cur->_kv.first < kv.first)
      {
        parent = cur;
        cur = cur->_right;
      }
      else if (cur->_kv.first > kv.first)
      {
        parent = cur;
        cur = cur->_left;
      }
      else
      {
        return false;
      }
    }
    //确定cur节点和p节点的位置关系
    cur = new Node(kv);
    if (parent->_kv.first < kv.first)
    {
      parent->_right = cur;
    }
    else
    {
      parent->_left = cur;
    }
    cur->_parent = parent;
    while (parent && parent->_col == RED)
    {
      Node* grandfather = parent->_parent;
      if (parent == grandfather->_left)
      {
        Node* uncle = grandfather->_right;
        //情况一
        if (uncle && uncle->_col == RED)
        {
          parent->_col = uncle->_col = BLACK;
          grandfather->_col = RED;
          //向上处理
          cur = grandfather;
          parent = cur->_parent;
        }
        else//情况2
        {
          if (cur == parent->_left)
          {
            //      g
            //    p    u
            //  c
            RotateR(grandfather);
            parent->_col = BLACK;
            grandfather->_col = RED;
          }
          else
          {
            //      g
            //    p    u
            //      c
            RotateL(parent);
            RotateR(grandfather);
            cur->_col = BLACK;
            grandfather->_col = RED;
          }
          break;//旋转完的子树的根节点必为黑,这时就不用向上调整处理了
        }
      }
      else
      {
        Node* uncle = grandfather->_left;
        // 情况一:叔叔存在且为红
        if (uncle && uncle->_col == RED)
        {
          // 变色
          parent->_col = uncle->_col = BLACK;
          grandfather->_col = RED;
          // 继续往上处理
          cur = grandfather;
          parent = cur->_parent;
        }
        else//情况2
        {
          if (cur == parent->_right)
          {
            //      g
            //    u    p
            //           c
            RotateL(grandfather);
            parent->_col = BLACK;
            grandfather->_col = RED;
          }
          else
          {
            //      g
            //    u    p
            //        c
            RotateR(parent);
            RotateL(grandfather);
            cur->_col = BLACK;
            grandfather->_col = RED;
          }
          break;//旋转完的子树的根节点必为黑,这时就不用向上调整处理了
        }
      }
    }
    _root->_col = BLACK;
    return true;
  }

验证

void TestRBTree1()
{
  int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
  RBTree<int, int> t;
  for (auto e : a)
  {
    t.Insert(make_pair(e, e));
  }
  t.InOrder();
  cout << t.IsBalance() << endl;
}

bool Check(Node* cur, int blackNum, int refBlackNum)
  {
    if (cur == nullptr)
    {
      //当节点为空时,表示这条路径结束,这时就要对黑色节点进行判断
      if (refBlackNum != blackNum)
      {
        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);
  }
  bool IsBalance()
  {
    if (_root && _root->_col == RED)
      return false;
    //统计一条路径的黑色节点数
    int refBlackNum = 0;
    Node* cur = _root;
    while (cur)
    {
      if (cur->_col == BLACK)
      {
        refBlackNum++;
      }
      cur = cur->_left;
    }
    return Check(_root,0,refBlackNum);
  }

红黑树的性能测试

void TestRBTree2()
{
  const int N = 1000000;
  vector<int> v;
  v.reserve(N);
  srand(time(0));
  for (size_t i = 0; i < N; i++)
  {
    v.push_back(rand() + i);
  }
  //测插入所需时间
  size_t begin2 = clock();
  RBTree<int, int> t;
  for (auto a : v)
  {
    t.Insert(make_pair(a, a));
  }
  size_t end2 = clock();
  
  cout << "Insert:" << end2 - begin2 << endl;
  cout << t.IsBalance() << endl;
  //测高度,数量
  cout << "height" << t.Height() << endl;
  cout << "Size:" << t.Size() << endl;
  //测查找时间
  size_t begin1 = clock();
  for (size_t i = 0; i < N; i++)
  {
    t.Find((rand() + i));
  }
  size_t end1 = clock();
  cout << "Find:" << end1 - begin1 << endl;
}

原码

#pragma once
enum Colour
{
  RED,
  BLACK
};
template<class K,class V>
struct RBTreeNode
{
  RBTreeNode<K, V>* _left;
  RBTreeNode<K, V>* _right;
  RBTreeNode<K, V>* _parent;
  pair<K, V> _kv;
  Colour _col;
  RBTreeNode(const pair<K, V>& kv)
    :_left(nullptr)
    , _right(nullptr)
    , _parent(nullptr)
    , _kv(kv)
    , _col(RED)
  {
  }
};
template<class K,class V>
class RBTree
{
  typedef RBTreeNode<K, V> Node;
public:
  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节点和p节点的位置关系
    cur = new Node(kv);
    if (parent->_kv.first < kv.first)
    {
      parent->_right = cur;
    }
    else
    {
      parent->_left = cur;
    }
    cur->_parent = parent;
    while (parent && parent->_col == RED)
    {
      Node* grandfather = parent->_parent;
      if (parent == grandfather->_left)
      {
        Node* uncle = grandfather->_right;
        //情况一
        if (uncle && uncle->_col == RED)
        {
          parent->_col = uncle->_col = BLACK;
          grandfather->_col = RED;
          //向上处理
          cur = grandfather;
          parent = cur->_parent;
        }
        else//情况2
        {
          if (cur == parent->_left)
          {
            //      g
            //    p    u
            //  c
            RotateR(grandfather);
            parent->_col = BLACK;
            grandfather->_col = RED;
          }
          else
          {
            //      g
            //    p    u
            //      c
            RotateL(parent);
            RotateR(grandfather);
            cur->_col = BLACK;
            grandfather->_col = RED;
          }
          break;//旋转完的子树的根节点必为黑,这时就不用向上调整处理了
        }
      }
      else
      {
        Node* uncle = grandfather->_left;
        // 情况一:叔叔存在且为红
        if (uncle && uncle->_col == RED)
        {
          // 变色
          parent->_col = uncle->_col = BLACK;
          grandfather->_col = RED;
          // 继续往上处理
          cur = grandfather;
          parent = cur->_parent;
        }
        else//情况2
        {
          if (cur == parent->_right)
          {
            //      g
            //    u    p
            //           c
            RotateL(grandfather);
            parent->_col = BLACK;
            grandfather->_col = RED;
          }
          else
          {
            //      g
            //    u    p
            //        c
            RotateR(parent);
            RotateL(grandfather);
            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;
    if (subRL)
      subRL->_parent = parent;
    subR->_left = parent;
    Node* ppnode = parent->_parent;
    parent->_parent = subR;
    if (parent == _root)
    {
      _root = subR;
      subR->_parent = nullptr;
    }
    else
    {
      if (ppnode->_left == parent)
      {
        ppnode->_left = subR;
      }
      else
      {
        ppnode->_right = subR;
      }
      subR->_parent = ppnode;
    }
  }
  void RotateR(Node* parent)
  {
    Node* subL = parent->_left;
    Node* subLR = subL->_right;
    parent->_left = subLR;
    if (subLR)
      subLR->_parent = parent;
    subL->_right = parent;
    Node* ppnode = parent->_parent;
    parent->_parent = subL;
    if (parent == _root)
    {
      _root = subL;
      subL->_parent = nullptr;
    }
    else
    {
      if (ppnode->_left == parent)
      {
        ppnode->_left = subL;
      }
      else
      {
        ppnode->_right = subL;
      }
      subL->_parent = ppnode;
    }
  }
  void _InOrder(Node* root)
  {
    if (root == nullptr)
      return;
    _InOrder(root->_left);
    cout << root->_kv.first << endl;
    _InOrder(root->_right);
  }
  void InOrder()
  {
    _InOrder(_root);
  }
  bool Check(Node* cur, int blackNum, int refBlackNum)
  {
    if (cur == nullptr)
    {
      //当节点为空时,表示这条路径结束,这时就要对黑色节点进行判断
      if (refBlackNum != blackNum)
      {
        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);
  }
  bool IsBalance()
  {
    if (_root && _root->_col == RED)
      return false;
    //统计一条路径的黑色节点数
    int refBlackNum = 0;
    Node* cur = _root;
    while (cur)
    {
      if (cur->_col == BLACK)
      {
        refBlackNum++;
      }
      cur = cur->_left;
    }
    return Check(_root,0,refBlackNum);
  }
  size_t Size()
  {
    return _Size(_root);
  }
  size_t _Size(Node* root)
  {
    if (root == NULL)
      return 0;
    return _Size(root->_left)
      + _Size(root->_right) + 1;
  }
  Node* Find(const K& key)
  {
    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 NULL;
  }
  int _Height(Node* root)
  {
    if (root == nullptr)
      return 0;
    int leftHeight = _Height(root->_left);
    int rightHeight = _Height(root->_right);
    return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
  }
  int Height()
  {
    return _Height(_root);
  }
private:
  Node* _root = nullptr;
};
void TestRBTree1()
{
  int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
  RBTree<int, int> t;
  for (auto e : a)
  {
    t.Insert(make_pair(e, e));
  }
  t.InOrder();
  cout << t.IsBalance() << endl;
}
//性能测试
void TestRBTree2()
{
  const int N = 1000000;
  vector<int> v;
  v.reserve(N);
  srand(time(0));
  for (size_t i = 0; i < N; i++)
  {
    v.push_back(rand() + i);
  }
  //测插入所需时间
  size_t begin2 = clock();
  RBTree<int, int> t;
  for (auto a : v)
  {
    t.Insert(make_pair(a, a));
  }
  size_t end2 = clock();
  
  cout << "Insert:" << end2 - begin2 << endl;
  cout << t.IsBalance() << endl;
  //测高度,数量
  cout << "height" << t.Height() << endl;
  cout << "Size:" << t.Size() << endl;
  //测查找时间
  size_t begin1 = clock();
  for (size_t i = 0; i < N; i++)
  {
    t.Find((rand() + i));
  }
  size_t end1 = clock();
  cout << "Find:" << end1 - begin1 << endl;
}
相关文章
|
3天前
|
存储 编译器 C++
C++:map&set 对红黑树的封装
C++:map&set 对红黑树的封装
11 1
|
3天前
|
存储 算法 Java
数据结构/C++:红黑树
数据结构/C++:红黑树
15 3
|
3天前
|
存储 算法 编译器
【C++入门到精通】C++入门 —— 红黑树(自平衡二叉搜索树)
【C++入门到精通】C++入门 —— 红黑树(自平衡二叉搜索树)
14 1
|
3天前
|
编译器 C++
【C++进阶】引用 & 函数提高
【C++进阶】引用 & 函数提高
|
3天前
|
关系型数据库 C++
【C++高阶(四)】红黑树深度剖析--手撕红黑树!
【C++高阶(四)】红黑树深度剖析--手撕红黑树!
|
3天前
|
存储 C++
【C++进阶(九)】C++多态深度剖析
【C++进阶(九)】C++多态深度剖析
|
3天前
|
编译器 C++
【C++进阶(八)】C++继承深度剖析
【C++进阶(八)】C++继承深度剖析
|
3天前
|
编译器 C语言 C++
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
|
3天前
|
设计模式 C语言 C++
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
|
3天前
|
存储 缓存 编译器
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比