C++红黑树的实现

红黑树

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出2倍,因而是接近平衡的 .

红黑树的性质
1.每个结点不是红色就是黑色
2.根节点是黑色的
3.如果一个节点是红色的,则它的两个孩子结点是黑色的
4.对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
5.每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

红黑树新节点的插入
1.按照搜索树的插入方法先插入到合适的叶子节点(插入的点默认红色)
2.根据红色节点是否连续,判断是否需要调整

如果需要调整:
cur是插入的节点
父节点p:指向cur的父节点
祖父节点g:指向p的父节点
叔叔节点u:g的另外一个孩子节点

先看p节点在g节点的那一边
(1)p在祖父节点左边, g->left == p;
再分为3种情况分别处理

<1>叔叔节点u存在且为红
将p,u改成黑色
g改成红色(g如果是根节点,最后在变成黑色)
cur= g继续向上调整

<2>u不存在/存在且是黑色
先看cur节点是否跟p节点一样在左边
不在就先调整cur:以p为轴,左旋
swap(cur,p)交换这俩的指向,再进行下一步	

<3>右旋,以g为轴
p调整为黑,g调整为红
结束调整

(2)p在祖父节点的右边,g->right == p;

<1>叔叔节点u存在且为红
 将p,u改成黑色
 g改成红色(g如果是根节点,最后在变成黑色)
 cur= g继续向上调整

 <2>u不存在/存在且是黑色
 先看cur节点是否跟p节点一样在右边
 if(cur==p->left)
 不在就先调整cur:以p为轴,右旋
 swap(cur,p)交换这俩的指向,再进行下一步 

 <3>左旋,以g为轴
 p调整为黑,g调整为红
 结束调整
#include <iostream>
#include <utility>
using namespace std;

//节点的颜色
enum Color
{
 BLACK,
 RED
};

//红黑树的定义
template<class k, class v>
struct RBNode
{
 pair<k, v> _value;
 Color _color;
 RBNode<k, v>* _parent;
 RBNode<k, v>* _left;
 RBNode<k, v>* _right;
 
 //默认构造,新插入节点颜色默认红色
 RBNode(const pair<k, v>& value = pair<k, v>())
  :_value(value)
  , _color(RED)  //
  , _parent(nullptr)
  , _left(nullptr)
  , _right(nullptr)
 {}
};

template<class k, class v>
class RBTree
{
public:
 typedef RBNode<k, v> Node;
 
 //头节点,指向根节点,头节点的左/右指向树的最左/最右节点
 RBTree()
  :_header(new Node)
 {
  _header->_left = _header->_right = _header;
 }
 
 //中序遍历
 void inorder()
 {
  _inorder(_header->_parent);
  cout << endl;
 }
 void _inorder(Node* root)
 {
  if (root)
  {
   _inorder(root->_left);
   cout << root->_value.first << " ";
   _inorder(root->_right);
  }
 }
 
 //右旋
 void RotateR(Node* parent)
 {
  Node* subL = parent->_left;
  Node* subLR = subL->_right;
  subL->_right = parent;
  parent->_left = subLR;
  if (subLR)
   subLR->_parent = parent;
  if (parent == _header->_parent)
  {
   _header->_parent = subL;
   subL->_parent = _header;
  }
  else
  {
   Node* g = parent->_parent;
   subL->_parent = g;
   if (g->_left == parent)
    g->_left = subL;
   else
    g->_right = subL;
  }
  parent->_parent = subL;
 }
 
 //左旋
 void RotateL(Node* parent)
 {
  Node* subR = parent->_right;
  Node* subRL = subR->_left;
  subR->_left = parent;
  parent->_right = subRL;
  if (subRL)
   subRL->_parent = parent;
  if (parent == _header->_parent)
  {
   _header->_parent = subR;
   subR->_parent = _header;
  }
  else
  {
   Node* g = parent->_parent;
   subR->_parent = g;
   if (g->_left == parent)
    g->_left = subR;
   else
    g->_right = subR;
  }
  parent->_parent = subR;
 }
 
 //节点插入
 bool insert(const pair<k, v>& val)
 {
 //空树
 if (_header->_parent == nullptr)
 {
  //创建第一个根节点
  Node* root = new Node(val);
  //根节点为黑色
  root->_color = BLACK;
  
  _header->_parent = root;
  root->_parent = _header;
  
  _header->_left = root;
  _header->_right = root;
  return true;
 }
 
 //非空树
 //按照搜索树插入方式插入
 Node* cur = _header->_parent;
 Node* parent = nullptr;
 while (cur) {
  parent = cur;
  if (cur->_value.first == val.first) {
   return false;
  }
  else if (cur->_value.first > val.first) {
   cur = cur->_left;
  }
  else {
   cur = cur->_right;
  }
 }
 
 cur = new Node(val);
 if (parent->_value.first < val.first) {
  parent->_right = cur;
 }
 else {
  parent->_left = cur;
 }
 cur->_parent = parent;
 
 // 调整: 修改颜色, 旋转
 while (cur != _header->_parent && cur->_parent->_color == RED) {
  Node* p = cur->_parent;
  Node* g = p->_parent;
  //p节点在g节点的左边
  if (g->_left == p) {
   Node* u = g->_right;
   //u存在且为红
   if (u && u->_color == RED) {
    //修改颜色
    u->_color = p->_color = BLACK;
    g->_color = RED;
    //继续向上查看
    cur = g;
   }
   else {
    //u不存在/u存在且为黑
    //cur
    if (cur == p->_right) {
     RotateL(p);
     swap(cur, p);
    }
    //cur在p的左边,右旋
    RotateR(g);
    //修改颜色
    p->_color = BLACK;
    g->_color = RED;
    break;
   }
  }
  //p节点在g节点的右边
  else {
   Node* u = g->_left;
    //u存在且为红
   if (u && u->_color == RED) 
   {
    //修改颜色
    u->_color = p->_color = BLACK;
    g->_color = RED;
    //继续向上查看
    cur = g;
   }
   else 
   {
    //u不存在/u存在且为黑
    if (cur == p->_left)
    {
     RotateR(p);
     swap(cur, p);
    }
    //cur在p的左边,右旋
    RotateL(g);
    //修改颜色
    p->_color = BLACK;
    g->_color = RED;
    break;
   }
  }
 }
 
 //根颜色置为黑色
 _header->_parent->_color = BLACK;
 //更新_header的左,右
 _header->_left = leftMost();
 _header->_right = rightMost();
 return true;
 }
 
 //最左节点
 Node* leftMost() 
 {
  Node* cur = _header->_parent;
  while (cur && cur->_left) {
   cur = cur->_left;
  }
  return cur;
 }
 
 //最右节点
 Node* rightMost()
 {
  Node* cur = _header->_parent;
  while (cur && cur->_right)
   cur = cur->_right;
  return cur;
 }
 private:
 Node* _header;
};

void testRBTree()
{
 RBTree<int, int>  rbt;
 rbt.insert(make_pair(1, 1));
 rbt.insert(make_pair(2, 1));
 rbt.insert(make_pair(3, 1));
 rbt.insert(make_pair(4, 1));
 rbt.insert(make_pair(5, 1));
 rbt.insert(make_pair(0, 1));
 rbt.insert(make_pair(9, 1));
 rbt.insert(make_pair(8, 1));
 rbt.insert(make_pair(7, 1));
 rbt.insert(make_pair(6, 1));
 rbt.inorder();
}
int main() {
 testRBTree();
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值