红黑树

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

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

红黑树节点的定义

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)
	{}
};

红黑树结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点。
在这里插入图片描述
红黑树的插入操作
红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

  1. 按照二叉搜索的树规则插入新节点
template<class ValueType>
class RBTree
{
	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:
	PNode _pHead;
};
  1. 检测新节点插入后,红黑树的性质是否造到破坏
    因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了不能有连在一起的红色节点的性质。
    在这里插入图片描述

红黑树的验证
红黑树的检测分为两步:

  1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)
  2. 检测其是否满足红黑树的性质

bool IsValidRBTree()
{
	PNode pRoot = GetRoot();
	// 空树也是红黑树
	if (nullptr == pRoot)
		return true;
	// 检测根节点是否满足情况
	if (BLACK != pRoot->_color)
	{
		cout << "违反红黑树性质二:根节点必须为黑色" << endl;
		return false;
	}
	// 获取任意一条路径中黑色节点的个数
	size_t blackCount = 0;
	PNode pCur = pRoot;
	while (pCur)
	{
		if (BLACK == pCur->_color)
			blackCount++;
		pCur = pCur->_pLeft;
	}
	// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
	size_t k = 0;
	return _IsValidRBTree(pRoot, k, blackCount);
}
bool _IsValidRBTree(PNode 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++;
	// 检测当前节点与其双亲是否都为红色
	PNode 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);
}

红黑树模拟实现STL中的map与set

红黑树的迭代器
想要用红黑树实现STL的map和set的话,就需要涉及到关于红黑树的迭代器的问题,它的好处是可以方便遍历,使数据结构的底层实现与用户的透明。(begin()可以放在红黑树中最小节点,end()放在最大节点的下一个位置,则头结点位置)

改造红黑树

// 因为关联式容器中存储的是<key, value>的键值对,因此
// k为key的类型,
// ValueType: 如果是map,则为pair<K, V>; 如果是set,则为k
// KeyOfValue: 通过value来获取key的一个仿函数类
template<class K, class ValueType, class KeyOfValue>
class RBTree
{
	typedef RBTreeNode<ValueType> Node;
	typedef Node* PNode;
public:
	typedef RBTreeIterator<ValueType, ValueType*, ValueType&> Iterator;
public:
	RBTree();
	~RBTree()
		// Iterator
		Iterator Begin() { return Iterator(_pHead->_pLeft); }
	Iterator End() { return Iterator(_pHead); }
	// Modify
	pair<Iterator, bool> Insert(const ValueType& data)
	{
		// 插入节点并进行调整
		// 参考上文...
		return make_pair(Iterator(pNewNode), true);
	}
	// 将红黑树中的节点清空
	void Clear();
	Iterator Find(const K& key);
	// capacity
	size_t Size()const;
	bool Empty()const;
private:
	PNode _pHead;
	size_t _size; // 红黑树中有效节点的个数
};

set的模拟实现
set的底层结构就是红黑树,因此在set中直接封装一棵红黑树,然后将其接口包装下即可

template <class K>
class Set
{
	struct SetKeyOfValue
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	typedef typename RBTree<K, K, SetKeyOfValue>::iterator iterator;
	pair<iterator, bool> insert(const K& key)
	{
		return _rbt.insert(key);
	}
private:
	RBTree<K, K, SetKeyOfValue> _rbt;
};


map的模拟实现
map的底层结构就是红黑树,因此在map中直接封装一棵红黑树,然后将其接口包装下即可

#include "RBTree.hpp"

template <class K, class V>
class Map
{
	struct MapKeyOfValue
	{
		const K& operator()(const pair<K, V>& value)
		{
			return value.first;
		}
	};
public:
	typedef typename RBTree<K, pair<K, V>, MapKeyOfValue>::iterator iterator;

	iterator begin()
	{
		return _rbt.begin();
	}

	iterator end()
	{
		return _rbt.end();
	}

	pair<iterator, bool> insert(const pair<K, V>& value)
	{
		return _rbt.insert(value);
	}

	V& operator[](const K& key)
	{
		pair<iterator, bool> ret = _rbt.insert(make_pair(key, V()));
		return ret.first->second;
	}
private:
	RBTree<K, pair<K, V>, MapKeyOfValue> _rbt;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值