C++之红黑树

Posted 卷毛小学僧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++之红黑树相关的知识,希望对你有一定的参考价值。

文章目录


前言

前面一节我们介绍了平衡搜索二叉树AVL树,我们知道,AVL树虽然查找效率很高,但是不能过多的修改,因为它为了保持平衡要不断的进行旋转。我们今天介绍的红黑树也是一种平衡搜索树,不过它所要求的平衡没有AVL树那么严格,因此对它进行修改操作时所要进行的旋转比AVL树要进行的旋转少。


一、概念

红黑树,一种二叉搜索树,它额外在每一个结点上增加一个表示结点颜色的存储位,有Red和Black两种可能
通过对任意一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长处二倍,因此它是接近平衡的。

二、性质

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

三、结点的定义

//结点的颜色
	enum color
	
		RED,
		BLACK
	;
//结点的定义
	template<typename T>
	struct RBnode//红黑树的结点(三叉链)
	
		RBnode(T data)
		:_data(data)
		, _parent(nullptr)
		, _left(nullptr)
		, _right(nullptr)
		, col(RED)
		
		T _data;//数据
		RBnode* _parent;//父节点(为了方便实现旋转)
		RBnode* _left;//左孩子
		RBnode* _right;//右孩子
		color _col;//颜色
	;

看到这里,相信大家会有一个疑问:为什么默认新插入的结点颜色是红色?
答:如果我们将新结点的颜色设置为黑色,那么它一定会违背性质4(即,对于每一个结点,从该节点到其所有后代叶子结点的简单路径上,均包含相同数目的黑色结点),这样我们就需要大幅度的在这棵树上进行调整(几乎需要所有路径进行调整),才能使它再次符合性质4;
如果我们将新结点颜色设置为红色,它有可能违背性质3(即,如果一个结点是红色,那么它的两个孩子结点是黑色),也有一定的可能不违背,即使违背性质3它所带来的后果比违背性质4严重性小很多,我们可以通过几次旋转(只对它所在的路径进行调整)使它重新符合性质3。
因为我们新插入一个结点,它不是黑色就是红色,因此一定会违反一条性质,我们选择违反后果较小的性质3。

四、红黑树的结构

五、插入操作

1.插入代码

		bool insert(const pair<K, V>& kv)
		
			Node* newnode = new RBnode<K,V>(kv);
			if (!_root)//如果根节点为空,则新插入的结直接就是根节点
			
				_root = newnode;
			
			else
			
				Node* cur = _root;
				Node* parent = cur;
				while (cur)
				
					parent = cur;
					if (cur->_kv.first > kv.first)
					
						cur = cur->_left;
					
					else if (cur->_kv.first < kv.first)
					
						cur = cur->_right;
					
					else//树中已经有这个结点,插入失败
					
						return false;
					
				
				cur = newnode;
				if (parent->_kv.first > cur->_kv.first)
				
					parent->_left = cur;
				
				else
				
					parent->_right = cur;
				
				cur->_parent = parent;
				Node* Grandpa = parent->_parent;
				Node* uncle = nullptr;
				while(Grandpa && parent->_col == RED)//如果父节点不是黑色,且父节点不是根结点
				
					if (parent == Grandpa->_left)//定义叔叔结点
					
						uncle = Grandpa->_right;
					
					else
					
						uncle = Grandpa->_left;
					
					if (uncle->_col == RED)//如果叔叔存在且为红
					
						Grandpa->_col = RED;
						parent->_col = uncle->_col = BLACK;
					
					else//如果叔叔不存在,或者存在且为黑
					
						//p是g的右孩子,c是p的右孩子(左单旋)
						if (parent == Grandpa->_right && cur == parent->_right)
						
							Rotetal(Grandpa);
							Grandpa->_col = RED;
							parent->_col = BLACK;
						
						//p是g的左孩子,c是p的左孩子(右单旋)
						else if (parent == Grandpa->_left && cur == parent->_left)
						
							Rotetal(Grandpa);
							Grandpa->_col = RED;
							parent->_col = BLACK;
						
						//p是g的左孩子,c是p的右孩子(左右双旋)
						else if (parent == Grandpa->_left && cur == parent->_right)
						
							//先以parent为轴进行左单旋
							Rotetal(parent);
							//再以Grandpa为轴进行右单旋
							Rotetar(Grandpa);
							//更新颜色
							cur->_col = BLACK;
							Grandpa->_col = parent->_col = RED;
						
						//p是g的右孩子,c是p的左孩子(右左双旋)
						else if (parent == Grandpa->_right && cur == parent->_left)
						
							//先以parent为轴进行右单旋
							Rotetar(parent);
							//再以Grandpa为轴进行左单旋
							Rotetal(Grandpa);
							//更新颜色
							cur->_col = BLACK;
							Grandpa->_col = parent->_col = RED;
						
						//旋转之后就符合性质4了,因此不用再继续更新
						break;
					
					cur = parent;
					parent = Grandpa;
					Grandpa = Grandpa->_parent;
				
				if (_root->_col == RED)//如果到最后更新到根节点,导致根节点为红色,为了满足性质2(根节点是黑色),就要将根结点置为黑色
				
					_root->_col = BLACK;
				
			
			return true;
		

2.左单旋

		//左单旋
		void Rotetal(Node* parent)
		
			Node* SubR = parent->_right;
			Node* SubRL = SubR->_left;
			Node* Grandpa = parent->_parent;
			parent->_parent = SubR;
			parent->_right = SubRL;
			if (SubRL)
			
				SubRL->_parent = parent;
			
			SubR->_parent = Grandpa;
			if (!Grandpa)
			
				_root = SubR;
				_root->_parent = nullptr;
			
			else
			
				if (parent == Grandpa->_left)
				
					Grandpa->_left = SubR;
				
				else
				
					Grandpa->_right = SubR;
				
			
			SubR->_left = parent;
		

3.右单旋

		//右单旋
		void Rotetar(Node* parent)
		
			Node* SubL = parent->_left;
			Node* SubLR = SubL->_right;
			Node* Grandpa = parent->_parent;
			parent->_parent = SubL;
			parent->_left = SubLR;
			if (SubLR)
			
				SubLR->_parent = parent;
			
			SubL->_parent = Grandpa;
			if (!Grandpa)
			
				_root = SubL;
				_root->_parent = nullptr;
			
			else
			
				if (parent == Grandpa->_left)
				
					Grandpa->_left = SubL;
				
				else
				
					Grandpa->_right = SubL;
				
			
			SubL->_right = parent;
		

4.插入新结点的情况分析与总结

第一步、按照搜索二叉树的规则插入新结点

如果该树是空树,就让新结点作为它的根节点。
先找到要插入的位置,比当前结点小就向左子树寻找,比当前结点大就向右子树寻找。

第二步、分析插入结点后红黑树的性质是否被破坏

新结点默认为红色,
1.如果双亲节点的颜色是黑色,则没有违反红黑树性质,不需要调整;
2.如果双亲节点的颜色是红色,则违反性质4需要进行调整。
为了方便分析,我们约定当前结点为cur©,当前节点的父节点为parent§,当前节点的祖父结点为Grandpa(g),当前结点的叔叔结点为uncle(c).。

  • 情况一:c为红色,p为红,g为黑,u存在且为红

    只需要将p和u的颜色置为黑色,g的颜色置为红色。
    如果g是根节点,调整之后只需要将g改为黑色即可;
    如果g是子树,那么g一定有双亲结点,如果g的双亲结点为红色,就需要继续向上调整。
  • 情况二:cur为红,p为红,g为黑,u不存在/存在且为黑
    1. 如果u不存在,则说明cur是新增节点。因为如果cur不是新增节点,那么cur和p一定有一个是黑色,那么就不满足性质4(每条路径上的黑色结点的个数相同);
    1. 如果u存在且为黑,则说明cur原本就存在且为黑。现在是红色是因为cur所在子树新增节点导致向上调整颜色的过程中将cur置为红色。
      这种情况有四种可能:
  • p是g的左孩子,c是p的左孩子;(要进行右单旋)
    以g为轴进行右单旋:

    更新结点p为黑色,cur和g为红色。
  • p是g的右孩子,c是p的右孩子;(要进行左单旋)
    以g为轴进行左单旋:

    更新结点p为黑色,cur和g为红色。
  • p是g的左孩子,c是p的右孩子;(要进行左右双旋)
    先以p为轴进行左单旋,再以g为轴进行右单旋:

    更新结点cur为黑色,p和g为红色。
  • p是g的右孩子,c是p的左孩子。(要进行右左双旋)
    先以p为轴进行左单旋,再以g为轴进行右单旋:

    更新结点cur为黑色,p和g为红色。

动态演示:

升序:

降序:

随机插入构建红黑树:

右旋转:

左旋转:

六、验证红黑树

验证红黑树分为两步:

1.检测是否满足二叉搜索树

中序遍历是否为有序序列

2.检测是否满足红黑树性质

代码如下:

		bool IsValidRBTree()//验证是否为红黑树
		
			Node* pRoot = GetRoot();
			// 空树也是红黑树
			if (nullptr == pRoot)
				return true;
			// 检测根节点是否满足情况
			if (BLACK != pRoot->_col)
			
				cout << "违反红黑树性质二:根节点必须为黑色" << endl;
				return false;
			
			// 获取任意一条路径中黑色节点的个数
			size_t blackCount = 0;
			Node* pCur = pRoot;
			while (pCur)
			
				if (BLACK == pCur->_col)
					blackCount++;
				pCur = pCur->_left;
			
			// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
			size_t k = 0;
			return _IsValidRBTree(pRoot, k, blackCount);
		
		bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount)
		
			//走到null之后,判断k和black是否相等
			if (nullptr == pRoot)
			
				if (k != blackCount)
				
					cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
					return false;
				
				return true;
			
			// 统计黑色节点的个数
			if (BLACK == pRoot->_col)
				k++;
			// 检测当前节点与其双亲是否都为红色
			Node* pParent = pRoot->_parent;
			if (pParent && RED == pParent->_col && RED == pRoot->_col)
			
				cout << "违反性质三:没有连在一起的红色节点" << endl;
				return false;
			
			return _IsValidRBTree(pRoot->_left, k, blackCount) &&
				_IsValidRBTree(pRoot->_right, k, blackCount);
		

七、红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是O( l o g 2 N log_2 N log2N),红黑树不追求绝对平衡,只要保证最长路径不超过最短路径的两倍。相对而言,插入和旋转的次数更少,在经常进行增删的结构中性能比AVL树更优,而且红黑树的实现比AVL树简单,因此更加常用。


总结

以上就是今天要讲的内容,本文介绍了C++中红黑树的相关概念。本文作者目前也是正在学习C++相关的知识,如果文章中的内容有错误或者不严谨的部分,欢迎大家在评论区指出,也欢迎大家在评论区提问、交流。
最后,如果本篇文章对你有所启发的话,希望可以多多支持作者,谢谢大家!

数据结构之红黑树

红黑树

文章目录


本篇博文只讲解了红黑树的插入操作,下面我们来了解一下什么是红黑树。

红黑树的概念

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

NIL是空结点,这里显示出来是为了表示路径

红黑树和AVLTree不同点:

AVLTree:左右高度差不超过1,严格平衡

红黑树:最长路径不超过最短路径的2倍,近似平衡

严格来说红黑树的效率没有AVLTree高,当AVLTree的旋转多时,此时红黑树的效率就高于AVLTree

红黑树的性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点必须是黑色的

树里面没有连续的红色节点

  1. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点

每条路径都有相同数量的黑色节点(路径不是走到叶子节点,而是走到空节点)

  1. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点),就像图中的NIL节点

那么是红黑树是如何做到平衡的呢?

通过性质3和4:

由性质四可知,每条路径都有相同的黑色节点,假设有一条路径上都是黑色节点,那么一棵红黑树的最短路径就是这条路径

由性质三可知,红黑树中没有连续的红色节点,那么一棵红黑树的最长路径就是一黑一红,交替出现,因为每条路径的黑色节点是相同的,最长路径不会超过最短路径的两倍

红黑树节点的定义

红黑树节点的颜色我们可以用枚举来定义,我们将红黑树实现成三叉链的结构:

#pragma once
enum Colour

    BLACK,
    RED
;
template<class K,class V>
struct RBTreeNode

    RBTreeNode<K,V>* _left;
    RBTreeNode<K,V>* _right;
    RBTreeNode<K,V>* _parent;
    
    Colour _col;//颜色
    
    pair<K,V> _kv;//键值对
    
    //构造函数
    RBTreeNode(const pair<K,V>& kv)
        :_left(nullptr),
        :_right(nullptr),
        :_parent(nullptr),
        :col(RED),
        :_kv(kv)
	
;

有一个问题:为什么颜色初始化,初始化成红色呢?

插入红色可能破坏规则3,但是插入黑色的话一定破坏规则4,因为如果插入黑色节点,该路径黑色节点的数目肯定发生了变化,为了保证所有路径黑色节点数目相同,所有路径都需要做调整,而插入红色,如果父亲节点是黑色节点,那么就不需要做调整,即使出现了连续的红色节点,破坏了规则3,只是破坏了这一条路径,只需要调整该路径,所以选择红色节点

红黑树的插入情况操作

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

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

解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

插入cur时,已经出现了连续的红节点,所以需要将p变黑,为了保证不同路径的黑色节点数目不变,u也得变黑,那么为什么最后将g改为红呢?因为这棵树可能只是局部的子树,那么要保持他的每条路径黑色节点的数量不变,p和u变黑以后,路径上的黑色节点多了,所以g得变红,g变红一会就得继续往上处理

具象图1:

处理结果:

具象图二(需要继续往上处理的场景):

如果g是根节点,调整完成后,需要将g改为黑色
如果g是子树,g一定有双亲,且g的双亲如果是红色,需要继续向上调整

  • 插入情况二:cur为红,p为红,g为黑,u不存在/u存在且为黑

关键看叔叔,情况二相比情况一,只变了叔叔

u存在且为黑:

u存在且为黑的情况时,cur一定不是新增,cur原来是黑的,保证了规则4,cur之所以是红色,是因为cur是作为子树的祖父,是由第一种情况变化过来的

该情况是由情况一转变过来的:

u不存在:

u不存在,那么cur就是新增,因为cur不是新增的话,那么p和cur当中一定有一个黑色节点,此时黑色节点就多了,不满足规则4:每条路径黑色节点数目相同

处理方法:

叔叔不存在时:

p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转,p、g变色–p变黑,g变红

叔叔存在且为黑:

  • 插入情况三:cur为红,p为红,g为黑,u不存在/u存在且为黑

插入情况三相比于插入情况二不一样的是,p如果是p的左边,那么cur就是p的右边,p如果是p的右边,那么cur就是p的左边

这种情况做一次旋转是解决不了问题的,需要做两次旋转:

p为g的左孩子,cur为p的右孩子时,则针对p做左单旋转,然后再针对g做右单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转,再针对g做左单旋转

u不存在:

u存在且为黑:

红黑树的插入代码

bool Insert(const pair<K, V>& kv)

    if (_root == nullptr)
    
        _root = new Node(kv);
        _root->_col = BLACK;//根节点必须是黑色
        return true;
    
    Node* parent = nullptr;
    Node* cur = _root;
    while (cur)
    
        if (cur->_kv.first < kv.first)
        
            parent = cur;
            cur = cur->_right;
        
        else if (cur->_kv.first > kv.first)
        
            parent = cur;
            cur = cur->_left;
        
        else
        
            //相等
            return false;
        
    

    cur = new Node(kv);
    cur->_col = RED;//默认给红色

    //链接
    if (parent->_kv.first < cur->_kv.first)
    
        parent->_right = cur;
        cur->_parent = parent;
    
    else
    
        parent->_left = cur;
        cur->_parent = parent;
    

    //控制平衡,控制颜色
    while (parent && parent->_col == RED)
    
        Node* grandfather = parent->_parent;
        if (parent == grandfather->_right)
        
            //找到叔叔
            Node* uncle = grandfather->_left;
            //情况一:uncle存在且为红,进行变色处理即可,并且继续往上更新处理
            if (uncle && uncle->_col == RED)
            
                parent->_col = uncle->_col = BLACK;
                grandfather->_col = RED;

                cur = grandfather;
                parent = cur->_parent;
            
            //情况二+三:uncle不存在,uncle存在且为黑,进行旋转+变色处理
            else
            
                //情况二:单旋+变色
                if (cur == parent->_left)
                
                    RotateR(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                
                else
                
                    //情况三:双旋+变色
                    RotateL(parent);
                    RotateR(grandfather);
                    cur->_col = BLACK;
                    grandfather->_col = RED;
                
                break;
            
        
        else//parent == greandfather->_left
        
            Node* uncle = grandfather->_right;
            if (uncle && uncle->col == RED)
            
                parent->_col = uncle->_col = BLACK;
                grandfather->_col = RED;

                cur = grandfather;
                parent = cur->_parent;
            
            else
            
                if (parent->_right == cur)
                
                    RotateL(grandfather);
                    parent->_col = BLACK;
                    grandfather->COL = RED;
                
                else//parent->_left == cur
                
                    //双旋+变色
                    RotateR(parent);
                    RotateL(grandfather);
                    cur->_col = BLACK;
                    grandfather->_col = RED;
                
                //不用再继续了,不会有连续红色和黑色个数不一样
                break;
            
        
    
    _root->_col = BLACK;

void RotateR(Node* parent)

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

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

    Node* ppNode = parent->_parent;

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

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

        subL->_parent = ppNode;
    


void RotateL(Node* parent)

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

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

    Node* ppNode = parent->_parent;

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

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

        subR->_parent = ppNode;
    

红黑树测试代码

void TestRBTree1()

	//int a[] =  16, 3, 7, 11, 9, 26, 18, 14, 15 ;
	//int a[] =  4, 2, 6, 1, 3, 5, 15, 7, 16, 14 ;
	const int n = 1000000;
	vector<int> a;
	a.reserve(n);
	srand(time(0));
	for (size_t i = 0; i < n; ++i)
	
		a.push_back(rand());
	

	RBTree<int, int> t1;
	for (auto e : a)
	
		t1.Insert(make_pair(e, e));
	

	cout << t1.IsBalance() << endl;
	//t1.InOrder();

void _InOrder(Node* root)

    if(root == nullptr)
    
        return;
    
    _InOrder(root->_left);
    cout<<root->_kv.first<<endl;
    _InOrder(root->_right);

void InOrder(Node* root)

    _InOrder(_root);

bool CheckRR(Node* cur)

    if(cur == nullptr)
    
        return true;
    
    if(cur->_col == RED && cur->_parent == RED)
    
        cout<<"违反规则三,存在连续的红色节点"<<endl;
        return false;
    
    return CheckRR(cur->_left)
        && CheckRR(cur->_right);


bool CheckBlackNum(Node* cur,int blackNum,int benchmark)

    if(cur == nullptr)
    
        if(blackNum != benchmark)
        
            cout<<"违反规则四:黑色节点的数量不相等"<<endl;
            return false;
        
        return true;
    
    if(cur->_col == BLACK)
    
        ++blackNum;
    
    return CheckBlackNum(cur->_left,balckNum,benchmark);
    	&& CheckBlackNum(cur->_right,balckNum,benchmark);

bool IsBalance()

    if(_root == nullptr)
    
        return true;
    
    if(_root->_col == RED)
    
        cout<<"根节点是红色,违反规则二"<<endl;
        return false;
    
    //算出最左路径的黑色节点的个数作为基准值
    int benchmark = 0;
    Node* cur = _root;
    while(cur)
    
        if(cur->_col == BLACK)
        
            ++benchmark;
        
        cur = cur->_left;
    
    int blackNum = 0;
    //检查规则三
    return CheckRR(_root) && CheckBlackNum(root,blackNum,benchmark);
    //每条路径的黑色节点都求出来,提前算出一个基准值进行比较

红黑树整体代码

template<class K,class V>
class RBTree

    typedef RBTreeNode<K,V> Node;
public:
    RBTree()
        :_root(nullptr)
    
    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;
            
        
        //插入红色可能破坏规则3,插入黑色一定破坏规则4,破坏规则4比较难处理
        //新增节点就新增一个红色节点
        //1、如果新增节点的父亲是黑色,没有影响
        //2、如果新增节点的父亲是红色,则产生了连续的红色节点,破坏了规则3,需要分情况处理:
        
        cur = new Node(kv);
        cur->_col = RED;
        //插入链接
        if(parent->_kv.first < kv.first)
        
            parent->_right = cur;
            cur->_parent = parent;
        
        else
        
            parent->_left = cur;
            cur->_parent = parent;
        
        //控制平衡,控制颜色
        while(parent && parent->_col == RED)
        
            Node* grandfather = parent->_parent;
            if(parent == grandfather->_right)
            
                //找到叔叔
                Node* uncle = grandfather->_left;
                //情况一:uncle存在且为红,进行变色处理即可,并且继续往上更新处理
                if(uncle && uncle->_col == RED)
                
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    
                    cur = grandfather;
                    parent = cur->_parent;
                
                //情况二+三:uncle不存在,uncle存在且为黑,进行旋转+变色处理
                else
                
                    //情况二:单旋+变色
                    if(cur == parent->_left)
                    
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    
                    else
                    
                        //情况三:双旋+变色
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    
                    break;
                
            
            else//parent == greandfather->_left
            
                Node* uncle = grandfather->_right; 
                if(uncle && uncle ->col == RED)
                
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    
                    cur = grandfather;
                    parent = cur->_parent;
                
                else
                
                    if(parent->_right == cur)
                    
                        RotateL(grandfather);
                        parent->_col = BLACK;
                        grandfather->COL = RED;
                    
                    else//parent->_left == cur
                    
                        //

以上是关于C++之红黑树的主要内容,如果未能解决你的问题,请参考以下文章

C++从入门到入土第二十二篇:数据结构之红黑树

C++从入门到入土第二十二篇:数据结构之红黑树

C++从入门到入土第二十二篇:数据结构之红黑树

C++从入门到入土第二十二篇:数据结构之红黑树

数据结构与算法之红黑树

算法之红黑树