AVL树和红黑树(map和set的底层实现)

map和set的概念及使用

map和set的底层结构

map和set其底层都是按照二叉搜索树来实现的,但是二叉搜索树有其自身的缺陷,假如往树中插入的元素有序或者接近有序,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map、set等关联式容器的底层结构是对二叉树进行了平衡处理,即采用平衡树来实现。

AVL树

AVL树的概念

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
    AVL树和红黑树(map和set的底层实现)_第1张图片
    如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O(logN),搜索时间复杂度O(logN )。

AVL树节点的定义

template<class K, class V>
struct AVLTreeNode
{
	pair<K, V> _val;
	AVLTreeNode<K, V>* _pLeft;
	AVLTreeNode<K, V>* _pRight;
	AVLTreeNode<K, V>* _pParent;
	int _bf;
	AVLTreeNode(const pair<K,V>& val)
		:_val(val)
		, _pLeft(nullptr)//该节点的左孩子
		, _pRight(nullptr)//该节点的右孩子
		, _pParent(nullptr)//该节点的父节点
		, _bf(0)//该节点的平衡因子
	{}
};

AVL树的插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么AVL树的插入过程可以分为两步:

  1. 按照二叉搜索树的方式插入新节点
  2. 调整节点的平衡因子
bool Insert(const pair<K, V> kv)
	{
	// 1. 先按照二叉搜索树的规则将节点插入到AVL树中
    // ...
    
    // 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,此时就需要更新平衡因子,并检测是否破坏了AVL树的平衡性
    
    /*
     pCur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:
      1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可
      2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可
      此时:pParent的平衡因子可能有三种情况:0,正负1, 正负2
      1. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整成0,此时满足AVL树的性质,插入成功
      2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1,此时以pParent为根的树的高度增加,需要继续向上更新
      3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进行旋转处理
    */
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_bf = 0;
			return true;
		}
		Node* Parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_val.first > kv.first)
			{
				Parent = cur;
				cur = cur->_pLeft;
			}
			else if (cur->_val.first < kv.first)
			{
				Parent = cur;
				cur = cur->_pRight;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(kv);
		if (Parent->_val > cur->_val)
		{
			Parent->_pLeft = cur;
			cur->_pParent = Parent;
		}
		else
		{
			Parent->_pRight = cur;
			cur->_pParent = Parent;
		}
		while (Parent)
		{
			if (cur == Parent->_pLeft)
				Parent->_bf--;
			else
			{
				Parent->_bf++;
			}
			if (Parent->_bf == 0)
				break;
			else if (abs(Parent->_bf) == 1)
			{
				cur = Parent;
				Parent = Parent->_pParent;
			}
			else if (abs(Parent->_bf) == 2)
			{
				if (Parent->_bf == 2){
					if (cur->_bf == 1){
						RotateL(Parent);
					}
					else if (cur->_bf == -1){
						RotateRL(Parent);
					}
				}
				else if (Parent->_bf == -2){
					if (cur->_bf == -1){
						RotateR(Parent);
					}
					else if (cur->_bf == 1){
						RotateLR(Parent);
					}
				}
				break;
			}
			else
			{
				assert(false);
			}
		}
		return true;
	}

AVL树的旋转

如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:

1. 新节点插入较高左子树的左侧—左左:右单旋

AVL树和红黑树(map和set的底层实现)_第2张图片

/*
  上图在插入前,AVL树是平衡的,新节点插入到30的左子树(注意:此处不是左孩子)中,30左子树增
加
  了一层,导致以60为根的二叉树不平衡,要让60平衡,只能将60左子树的高度减少一层,右子树增加
一层,
  即将左子树往上提,这样60转下来,因为60比30大,只能将其放在30的右子树,而如果30有右子
树,右子树根的值一定大于30,小于60,只能将其放在60的左子树,旋转完成后,更新节点的平衡因子
即可。在旋转过程中,有以下几种情况需要考虑:
  1. 30节点的右孩子可能存在,也可能不存在
  2. 60可能是根节点,也可能是子树
     如果是根节点,旋转完成后,要更新根节点
     如果是子树,可能是某个节点的左子树,也可能是右子树
     
 同学们再此处可举一些详细的例子进行画图,考虑各种情况,加深旋转的理解
*/
void _RotateR(PNode pParent)
{
    // pSubL: pParent的左孩子
    // pSubLR: pParent左孩子的右孩子,注意:该
    PNode pSubL = pParent->_pLeft;
    PNode pSubLR = pSubL->_pRight;
 
    // 旋转完成之后,30的右孩子作为双亲的左孩子
    pParent->_pLeft = pSubLR;
    // 如果30的左孩子的右孩子存在,更新亲双亲
    if(pSubLR)
        pSubLR->_pParent = pParent;
 
    // 60 作为 30的右孩子
    pSubL->_pRight = pParent;
    // 因为60可能是棵子树,因此在更新其双亲前必须先保存60的双亲
    PNode pPParent = pParent->_pParent;
    
    // 更新60的双亲
    pParent->_pParent = pSubL;
    
    // 更新30的双亲
    pSubL->_pParent = pPParent;
 
    // 如果60是根节点,根新指向根节点的指针
    if(NULL == pPParent)
    {
        _pRoot = pSubL;
        pSubL->_pParent = NULL;
    }
    else
    {
         // 如果60是子树,可能是其双亲的左子树,也可能是右子树
        if(pPParent->_pLeft == pParent)
            pPParent->_pLeft = pSubL;
        else
            pPParent->_pRight = pSubL;
    }
 
    // 根据调整后的结构更新部分节点的平衡因子
    pParent->_bf = pSubL->_bf = 0;
}
2. 新节点插入较高右子树的右侧—右右:左单旋

AVL树和红黑树(map和set的底层实现)_第3张图片

//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_pRight;
		Node* subRL = subR->_pLeft;
		parent->_pRight = subRL;
		if (subRL)
			subRL->_pParent = parent;

		subR->_pLeft = parent;
		Node* ppNode = parent->_pParent;
		parent->_pParent = subR;

		if (parent == _root)
		{
			_root = subR;
			_root->_pParent = nullptr;
		}
		else
		{
			if (ppNode->_pLeft == subR)
				ppNode->_pLeft = subR;
			else
			{
				ppNode->_pRight = subR;
			}
			subR->_pParent = ppNode;
		}
		parent->_bf = subR->_bf = 0;
	}
3. 新节点插入较高左子树的右侧—左右:先左单旋再右单旋

AVL树和红黑树(map和set的底层实现)_第4张图片
将双旋变成单旋后再旋转,即:先对30进行左单旋,然后再对90进行右单旋,旋转完成后再考虑平衡因子的更新。

// 旋转之前,60的平衡因子可能是-1/0/1,旋转完成之后,根据情况对其他节点的平衡因子进行调整
void _RotateLR(PNode pParent)
{
    PNode pSubL = pParent->_pLeft;
    PNode pSubLR = pSubL->_pRight;
    
    // 旋转之前,保存pSubLR的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节点的平
衡因子
    int bf = pSubLR->_bf;
    
    // 先对30进行左单旋
    _RotateL(pParent->_pLeft);
    
    // 再对90进行右单旋
    _RotateR(pParent);
 
    if(1 == bf)
        pSubL->_bf = -1;
    else if(-1 == bf)
        pParent->_bf = 1;
}
4. 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

AVL树和红黑树(map和set的底层实现)_第5张图片

void RotateRL(Node* parent)
	{
		Node* subR = parent->_pRight;
		Node* subRL = subR->_pLeft;
		int bf = subRL->_bf;	//保存subRL的平衡因子,因为在下面两行会置 0

		RotateR(parent->_pRight);
		RotateL(parent);

		if (bf == 0){
			parent->_bf = subRL->_bf = subR->_bf = 0;
		}
		else if (bf == 1){		//在c插入的新结点
			subR->_bf = 0;
			parent->_bf = -1;
			subRL->_bf = 0;
		}
		else if (bf == -1){		//在b插入的新结点
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
	}

总结:
假如以pParent为根的子树不平衡,即pParent的平衡因子为2或者-2,分以下情况考虑

  • pParent的平衡因子为2,说明pParent的右子树高,设pParent的右子树的根为pSubR
    • 当pSubR的平衡因子为1时,执行左单旋
    • 当pSubR的平衡因子为-1时,执行右左双旋
  • pParent的平衡因子为-2,说明pParent的左子树高,设pParent的左子树的根为pSubL
    • 当pSubL的平衡因子为-1是,执行右单旋
    • 当pSubL的平衡因子为1时,执行左右双旋

旋转完成后,原pParent为根的子树个高度降低,已经平衡,不需要再向上更新。

AVL树的验证

AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:

  1. 验证其为二叉搜索树
    如果中序遍历可得到一个有序的序列,就说明为二叉搜索树
  2. 验证其为平衡树
    每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)节点的平衡因子是否计算正确
int _Height(PNode pRoot);
bool _IsBalanceTree(PNode pRoot)
{
	// 空树也是AVL树
     if (nullptr == pRoot) return true;
    
     // 计算pRoot节点的平衡因子:即pRoot左右子树的高度差
     int leftHeight = _Height(pRoot->_pLeft);
     int rightHeight = _Height(pRoot->_pRight);
     int diff = rightHeight - leftHeight;
 
     // 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
     // pRoot平衡因子的绝对值超过1,则一定不是AVL树
     if (diff != pRoot->_bf || (diff > 1 || diff < -1))
         return false;
 
     // pRoot的左和右如果都是AVL树,则该树一定是AVL树
     return _IsBalanceTree(pRoot->_pLeft) && _IsBalanceTree(pRoot->_pRight);
 }

AVL树的删除

因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。

AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:

  • 插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。

因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

红黑树

红黑树的概念

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

红黑树的性质

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

红黑树节点的定义

// 节点的颜色
 enum Color{RED, BLACK};
 
 // 红黑树节点的定义
 template<class ValueType>
 struct RBTreeNode
 {
     RBTreeNode(const ValueType& data = ValueType(),Color color = RED)
         : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
         , _data(data), _color(color)
     {}
 
     RBTreeNode<ValueType>* _pLeft;   // 节点的左孩子
     RBTreeNode<ValueType>* _pRight;  // 节点的右孩子
     RBTreeNode<ValueType>* _pParent; // 节点的双亲(红黑树需要旋转,为了实现简单给出该字段)
     ValueType _data;            // 节点的值域
     Color _color;               // 节点的颜色
 };

红黑树结构

为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:
AVL树和红黑树(map和set的底层实现)_第7张图片

红黑树的插入操作

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

1. 按照二叉搜索的树规则插入新节点
template<class ValueType>
class RBTree{
	typedef RBTreeNode Node;
public:
	bool Insert(const ValueType& data)
	{
		……
		PNode& pRoot = GetRoot();
		if (nullptr == pRoot)
		{
			pRoot = new Node(data, BLACK);
			// 根的双亲为头节点
			pRoot->_pParent = _pHead;
			_pHead->_pParent = pRoot;
		}
		else
		{
			// 1. 按照二叉搜索的树方式插入新节点
			// 2. 检测新节点插入后,红黑树的性质是否造到破坏,
			//    若满足直接退出,否则对红黑树进行旋转着色处理
		}

		// 根节点的颜色可能被修改,将其改回黑色

		pRoot->_color = BLACK;
		_pHead->_pLeft = LeftMost();
		_pHead->_pRight = RightMost();
		return true;
	}
private:
	PNode& GetRoot(){ return _pHead->_pParent; }
	// 获取红黑树中最小节点,即最左侧节点
	PNode LeftMost();
	// 获取红黑树中最大节点,即最右侧节点
	PNode RightMost();
private:
	Node* _root;
};
2. 检测新节点插入后,红黑树的性质是否造到破坏

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:

  • 约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
    • 情况一: cur为红,p为红,g为黑,u存在且为红
      AVL树和红黑树(map和set的底层实现)_第8张图片
      解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
    • 情况二: cur为红,p为红,g为黑,u不存在/u为黑
      AVL树和红黑树(map和set的底层实现)_第9张图片
      p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,
      p为g的右孩子,cur为p的右孩子,则进行左单旋转
      p、g变色–p变黑,g变红
  • 情况三: cur为红,p为红,g为黑,u不存在/u为黑
    AVL树和红黑树(map和set的底层实现)_第10张图片
    p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,
    p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
    则转换成了情况2
pair<iterator, bool> Insert(const T& val){
		//插入节点
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->_color = BLACK;
			return make_pair(iterator(_root), true);
		}
		//寻找位置
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_data < val){
				parent = cur;
				cur = cur->_pRight;
			}
			else if (cur->_data > val){
				parent = cur;
				cur = cur->_pLeft;
			}
			else{
				return make_pair(iterator(cur), false);
			}
		}
		
		cur = new Node(val);
		Node* newnode = cur;
		cur->_color = RED;
		//插入适当位置
		if (parent->_data < val){
			parent->_pRight = cur;
			cur->_pParent = parent;
		}
		else{
			parent->_pLeft = cur;
			cur->_pParent = parent;
		}
		//变色处理
		//父节点为红色节点
		while (parent && parent->_color == RED){
			Node* grandfather = parent->_pParent;
			//父亲是祖父节点左孩子
			if (parent == grandfather->_pLeft){
				Node* uncle = grandfather->_pRight;
				// 1.叔叔节点存在且为红
				if (uncle && uncle->_color == RED){
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandfather->_color = RED;

					cur = grandfather;
					parent = cur->_pParent;
				}
				//叔叔节点不存在或者叔叔节点为黑
				else{
					if (cur == parent->_pRight){
						RotateL(parent);
						swap(parent, cur);
					}

					RotateR(grandfather);
					parent->_color = BLACK;
					grandfather->_color = RED;

					break;
				}
			}
			//父亲节点是祖父节点右孩子
			else{
				Node* uncle = grandfather->_pLeft;
				if (uncle && uncle->_color == RED){
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandfather->_color = RED;

					cur = grandfather;
					parent = cur->_pParent;
				}
				else{
					if (cur == parent->_pLeft){
						RotateR(parent);
						swap(parent, cur);
					}

					RotateL(grandfather);
					parent->_color = BLACK;
					grandfather->_color = RED;
					break;
				}
			}
		}

		_root->_color = BLACK;

		return make_pair(iterator(newnode), true);
	}

	void RotateL(Node* parent){
		Node* subR = parent->_pRight;
		Node* subRL = subR->_pLeft;

		parent->_pRight = subRL;
		if (subRL)
			subRL->_pParent = parent;

		subR->_pLeft = parent;
		Node* pNode = parent->_pParent;
		parent->_pParent = subR;

		if (parent == _root){
			_root = subR;
			_root->_pParent = nullptr;
		}
		else{
			if (pNode->_pLeft == parent)
				pNode->_pLeft = subR;
			else
				pNode->_pRight = subR;

			subR->_pParent = pNode;
		}

	}

	void RotateR(Node* parent){
		Node* subL = parent->_pLeft;
		Node* subLR = subL->_pRight;

		parent->_pLeft = subLR;
		if (subLR)
			subLR->_pParent = parent;

		subL->_pRight = parent;

		Node* pNode = parent->_pParent;
		parent->_pParent = subL;

		if (pNode == nullptr){
			_root = subL;
			_root->_pParent = nullptr;
		}
		else{
			if (pNode->_pLeft == parent){
				pNode->_pLeft = subL;
			}
			else{
				pNode->_pRight = subL;
			}

			subL->_pParent = pNode;
		}
	}

红黑树的验证

红黑树的检测分为两步:

  1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)
  2. 检测其是否满足红黑树的性质
bool IsValidRBTree(){
		Node* pRoot = _root;
		// 空树也是红黑树
		if (nullptr == pRoot)
			return true;

		// 检测根节点是否满足情况
		if (BLACK != pRoot->_color){
			cout << "违反红黑树性质二:根节点必须为黑色" << endl;
			return false;
		}

		// 获取任意一条路径中黑色节点的个数
		size_t blackCount = 0;
		Node* pCur = pRoot;
		while (pCur){
			if (BLACK == pCur->_color)
				blackCount++;

			pCur = pCur->_pLeft;
		}

		// 检测是否满足红黑树的性质,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->_color)
			k++;

		// 检测当前节点与其双亲是否都为红色
		Node* pParent = pRoot->_pParent;
		if (pParent && RED == pParent->_color && RED == pRoot->_color){
			cout << "违反性质三:没有连在一起的红色节点" << endl;
			return false;
		}

		return _IsValidRBTree(pRoot->_pLeft, k, blackCount) &&
			_IsValidRBTree(pRoot->_pRight, k, blackCount);
	}

红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(log N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

红黑树的迭代器

迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代器,需要考虑以前问题:

  • begin()与end()
    STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位置,end()放在最大节点
    (最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪块?能否给成nullptr呢?答案是行不通的,因为对end()位置的迭代器进行–操作,必须要能找最后一个元素,此处就不行,因此最好的方式是将end()放在头结点的位置:
    AVL树和红黑树(map和set的底层实现)_第11张图片
// 找迭代器的下一个节点,下一个节点肯定比其大
void Increasement()
{
    //分两种情况讨论:_pNode的右子树存在和不存在
    // 右子树存在
    if(_pNode->_pRight)
    {
         // 右子树中最小的节点,即右子树中最左侧节点
        _pNode = _pNode->_pRight;
        while(_pNode->_pLeft)
            _pNode = _pNode->_pLeft;
    }
    else
    {
         // 右子树不存在,向上查找,直到_pNode != pParent->right
        PNode pParent = _pNode->_pParent;
        while(pParent->_pRight == _pNode)
        {
            _pNode = pParent;
            pParent = _pNode->_pParent;
        }
 
        // 特殊情况:根节点没有右子树
        if(_pNode->_pRight != pParent)
            _pNode = pParent;
    }
}
 
// 获取迭代器指向节点的前一个节点
void Decreasement()
{
     //分三种情况讨论:_pNode 在head的位置,_pNode 左子树存在,_pNode 左子树不存在
     // 1. _pNode 在head的位置,--应该将_pNode放在红黑树中最大节点的位置
    if(_pNode->_pParent->_pParent == _pNode && _pNode->_color == RED)
        _pNode = _pNode->_pRight;
    else if(_pNode->_pLeft)
    {
        // 2. _pNode的左子树存在,在左子树中找最大的节点,即左子树中最右侧节点
        _pNode = _pNode->_pLeft;
        while(_pNode->_pRight)
            _pNode = _pNode->_pRight;
    }
    else
    {
         // _pNode的左子树不存在,只能向上找
        PNode pParent = _pNode->_pParent;
        while(_pNode == pParent->_pLeft)
        {
            _pNode = pParent;
            pParent = _pNode->_pParent;
        }
        _pNode = pParent;
    }
}

RBTree的完整代码

#include
using namespace std;

enum Color{
	RED,
	BLACK
};
template<class ValueType>
struct RBTreeNode
{
	RBTreeNode<ValueType>* _pLeft;
	RBTreeNode<ValueType>* _pRight;
	RBTreeNode<ValueType>* _pParent;
	ValueType _data;
	Color _color;
	RBTreeNode(const ValueType& data = ValueType(),Color color = RED)
		:_pLeft(nullptr)
		, _pRight(nullptr)
		, _pParent(nullptr)
		, _data(data)
		, _color(color)
	{}
};

template<class T,class Ptr,class Ref>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ptr, Ref> Self;
	Node* _node;
	RBTreeIterator(Node* node)
		:_node(node)
	{}
	Ref operator*(){
		return _node->_data;
	}
	Ref operator->(){
		return &_node->_data;
	}
	Self& operator++()
	{
		if (_node->_pRight != nullptr)
		{
			_node = _node->_pRight;
			while (_node->_pLeft != nullptr)
			{
				_node = _node->_pLeft;
			}
		}
		else
		{
			Node* parent = _node->_pParent;
			while (parent != nullptr && _node == parent->_pRight){
				_node = parent;
				parent = _node->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self operator++(int){
		Self tmp(*this);
		++(*this);
		return tmp;
	}
	Self& operator--(){
		if (_node->_pLeft != nullptr)
		{
			_node = _node->_pLeft;
			while (_node->_pLeft != nullptr)
			{
				_node = _node->_pRight;
			}
		}
		else
		{
			Node* parent = _node->_pParent;
			while (parent != nullptr && _node == parent->_pLeft){
				_node = parent;
				parent = _node->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	Self operator--(int){
		Self tmp(*this);
		--(*this);
		return tmp;
	}

	bool operator != (const Self& s) const{
		return _node != s._node;
	}

	bool operator == (const Self& s) const{
		return _node == s._node;
	}
};

template<class K, class T>
class RBTree{
	typedef RBTreeNode<T> Node;
public:
	typedef RBTreeIterator<T, T*, T&> iterator;
	typedef RBTreeIterator<T, const T*, const T&> const_iterator;

	RBTree() = default;
	// 拷贝构造 + operator=
	// 析构函数

	iterator begin(){
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}

		return iterator(cur);
	}

	iterator end(){
		return iterator(nullptr);
	}

	const_iterator begin() const{
		Node* cur = _root;
		while (cur && cur->_left){
			cur = cur->_left;
		}

		return const_iterator(cur);
	}

	const_iterator end() const{
		return const_iterator(nullptr);
	}
	
	pair<iterator, bool> Insert(const T& val){
		//插入节点
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->_color = BLACK;
			return make_pair(iterator(_root), true);
		}
		//寻找位置
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_data < val){
				parent = cur;
				cur = cur->_pRight;
			}
			else if (cur->_data > val){
				parent = cur;
				cur = cur->_pLeft;
			}
			else{
				return make_pair(iterator(cur), false);
			}
		}
		
		cur = new Node(val);
		Node* newnode = cur;
		cur->_color = RED;
		//插入适当位置
		if (parent->_data < val){
			parent->_pRight = cur;
			cur->_pParent = parent;
		}
		else{
			parent->_pLeft = cur;
			cur->_pParent = parent;
		}
		//变色处理
		//父节点为红色节点
		while (parent && parent->_color == RED){
			Node* grandfather = parent->_pParent;
			//父亲是祖父节点左孩子
			if (parent == grandfather->_pLeft){
				Node* uncle = grandfather->_pRight;
				// 1.叔叔节点存在且为红
				if (uncle && uncle->_color == RED){
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandfather->_color = RED;

					cur = grandfather;
					parent = cur->_pParent;
				}
				//叔叔节点不存在或者叔叔节点为黑
				else{
					if (cur == parent->_pRight){
						RotateL(parent);
						swap(parent, cur);
					}

					RotateR(grandfather);
					parent->_color = BLACK;
					grandfather->_color = RED;

					break;
				}
			}
			//父亲节点是祖父节点右孩子
			else{
				Node* uncle = grandfather->_pLeft;
				if (uncle && uncle->_color == RED){
					parent->_color = BLACK;
					uncle->_color = BLACK;
					grandfather->_color = RED;

					cur = grandfather;
					parent = cur->_pParent;
				}
				else{
					if (cur == parent->_pLeft){
						RotateR(parent);
						swap(parent, cur);
					}

					RotateL(grandfather);
					parent->_color = BLACK;
					grandfather->_color = RED;
					break;
				}
			}
		}

		_root->_color = BLACK;

		return make_pair(iterator(newnode), true);
	}

	void RotateL(Node* parent){
		Node* subR = parent->_pRight;
		Node* subRL = subR->_pLeft;

		parent->_pRight = subRL;
		if (subRL)
			subRL->_pParent = parent;

		subR->_pLeft = parent;
		Node* pNode = parent->_pParent;
		parent->_pParent = subR;

		if (parent == _root){
			_root = subR;
			_root->_pParent = nullptr;
		}
		else{
			if (pNode->_pLeft == parent)
				pNode->_pLeft = subR;
			else
				pNode->_pRight = subR;

			subR->_pParent = pNode;
		}

	}

	void RotateR(Node* parent){
		Node* subL = parent->_pLeft;
		Node* subLR = subL->_pRight;

		parent->_pLeft = subLR;
		if (subLR)
			subLR->_pParent = parent;

		subL->_pRight = parent;

		Node* pNode = parent->_pParent;
		parent->_pParent = subL;

		if (pNode == nullptr){
			_root = subL;
			_root->_pParent = nullptr;
		}
		else{
			if (pNode->_pLeft == parent){
				pNode->_pLeft = subL;
			}
			else{
				pNode->_pRight = subL;
			}

			subL->_pParent = pNode;
		}
	}



	iterator Find(const K& k){
		Node* cur = _root;
		while (cur){
			KeyOfValue kov;
			if (kov(cur->_data) < k){
				cur = cur->_pRight;
			}
			else if (kov(cur->_data) > k){
				cur = cur->_pLeft;
			}
			else{
				return iterator(cur);
			}
		}

		return end();
	}

	bool IsValidRBTree(){
		Node* pRoot = _root;
		// 空树也是红黑树
		if (nullptr == pRoot)
			return true;

		// 检测根节点是否满足情况
		if (BLACK != pRoot->_color){
			cout << "违反红黑树性质二:根节点必须为黑色" << endl;
			return false;
		}

		// 获取任意一条路径中黑色节点的个数
		size_t blackCount = 0;
		Node* pCur = pRoot;
		while (pCur){
			if (BLACK == pCur->_color)
				blackCount++;

			pCur = pCur->_pLeft;
		}

		// 检测是否满足红黑树的性质,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->_color)
			k++;

		// 检测当前节点与其双亲是否都为红色
		Node* pParent = pRoot->_pParent;
		if (pParent && RED == pParent->_color && RED == pRoot->_color){
			cout << "违反性质三:没有连在一起的红色节点" << endl;
			return false;
		}

		return _IsValidRBTree(pRoot->_pLeft, k, blackCount) &&
			_IsValidRBTree(pRoot->_pRight, k, blackCount);
	}

	void InOrder(){
		_InOrder(_root);
		cout << endl;
	}

	void _InOrder(Node* root){
		if (root == nullptr)
			return;

		_InOrder(root->_pLeft);
		cout << root->_data << " ";
		_InOrder(root->_pRight);
	}

private:
	Node* _root = nullptr;
};

void TestRBtree(){
	RBTree<int, int> t;
	int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14, };
 
	for (auto e : a){
		t.Insert(e);
	}
 
	t.InOrder();
	cout << t.IsValidRBTree() << endl;
}

map的模拟实现

#include"RBTree.h"

namespace fxl
{
	template<class K, class V>
	class map
	{
		typedef pair<K, V> ValueType;
		// 作用:将value中的key提取出来
		struct KeyOfValue
		{
			const K& operator()(const ValueType& v)
			{
				return v.first;
			}
		};
		typedef RBTree<K, ValueType, KeyOfValue> RBTree;
	public:
		typedef typename RBTree::Iterator iterator;
	public:
		map(){}

		iterator begin(){ return _t.Begin(); }
		iterator end(){ return _t.End(); }


		size_t size()const{ return _t.Size(); }
		bool empty()const{ return _t.Empty(); }

		V& operator[](const K& key)
		{
			return (*(_t.Insert(ValueType(key, V()))).first).second;
		}
		const V& operator[](const K& key)const;

		pair<iterator, bool> insert(const ValueType& data) { return _t.Insert(data); }
		void clear(){ _t.Clear(); }
		iterator find(const K& key){ return _t.Find(key); }
	private:
		RBTree _t;
	};
}

set的模拟实现

#include"RBTree.h"

namespace fxl
{
	template<class K>
	class set
	{
		typedef K ValueType;

		struct KeyOfValue
		{
			const K& operator()(const ValueType& key)
			{
				return key;
			}
		};

		// 红黑树类型重命名
		typedef RBTree<K, ValueType, KeyOfValue> RBTree;
	public:
		typedef typename RBTree::Iterator iterator;
	public:
		Set(){}

		iterator begin(){ return _t.Begin(); }
		iterator end(){ return _t.End(); }


		size_t size()const{ return _t.Size(); }
		bool empty()const{ return _t.Empty(); }

		pair<iterator, bool> insert(const ValueType& data)
		{
			return _t.Insert(data);
		}
		void clear(){ _t.Clear(); }
		iterator find(const K& key){ return _t.Find(key); }

	private:
		RBTree _t;
	};
}

你可能感兴趣的:(C++)