红黑树封装实现map和set

map和set

map和set 是STL中的容器,两者底层的实现都是参考文档:


map参考文档

在这里插入图片描述


set参考文档

在这里插入图片描述

两个容器底层都是去重的二叉搜索树实现的,一般使用高效的红黑树通过封装来实现。

红黑树的封装

先看一下原码:

在这里插入图片描述

在STL的原码中红黑树是有两个数据类型的树,map和set是通过控制模板类型的传递来生成不同数据类型的红黑树。

map传递:key 和 pair<key, value>

set传递: key 和 key

但是这样有导致了红黑树比较时不知道是使用单类型还是pair类来进行的比较,所以在参数传递时还会将传递仿函数,指定使用key进行比较

map的比较仿函数:

template<typename K, typename V>
struct MapValueOfT
{
	const K& operator()(const pair<K, V>& kv) const
	{
		return kv.first;
	}
};

set的比较类仿函数:

template<typename K>
struct SetValueOfT
{
	const K& operator()(const K& key) const
	{
		return key;
	}
};

那么在两者内部,红黑树都是这样的结构:

map的底层红黑树:

template<typename K, typename V> 
class map
{
public:
	typedef pair<K, V> valueType;
	typedef RBTree<K, valueType, MapValueOfT<K, V>> Tree;
	Tree _t;
}

set底层的红黑树:

template<typename K>
class set
{
public:
	typedef K valueType;
	typedef RBTree<K, valueType, SetValueOfT<K>> Tree;
	Tree _t;
}

红黑树的迭代器

begin() 和 end()

STL明确规定,begin()end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位置end() 放在最大节点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪块?

能否给成nullptr呢?答案是行不通的,因为对end()位置的迭代器进行–操作,必须要能找最后一个元素,此处就不行,因此最好的方式是将end()放在头结点的位置:

在这里插入图片描述

但是实现的红黑树的头结点是nullptr,我们只实现正向的迭代器:

operator++()

找迭代器的下一个节点,因为是中序遍历,所以分两种情况:

  1. 右子树存在

找右子树的最左节点

  1. 右子树不存在

右子树不存在,向上查找,直到 cur != parent->_right

Self& operator++()
{
	// 右子树不为空,就是找右子树中的最左节点
	if (_node->_right)
	{
		_node = _node->_right;
		while (_node->_left)
		{
			_node = _node->_left;
		}

	}
	else
	{
		// 右子树为空,找孩子不是父亲的右节点的父节点
		Node* parent = _node->_parent;
		while (parent && parent->_right == _node)
		{
			_node = parent;
			parent = parent->_parent;
		}
		_node = parent;
	}

	return *this;
}

operator–()

获取中序遍历的前一个节点,同样分两种情况:

  1. 左子树存在

在左子树中找最大的节点,即左子树中最右侧节点

  1. 左子树不存在

左子树不存在,向上查找,直到 cur != parent->_left

Self& operator--()
{
	// 左子树不为空,找左子树中的最右节点
	if (_node->_left)
	{
		_node = _node->_left;
		while (_node && _node->_left)
		{
			_node = _node->_left;
		}
	}
	else
	{
		// 左子树为空,找孩子不是父亲的左节点的父节点
		Node* parent = _node->_parent;
		while (parent && parent->_left == _node)
		{
			_node = parent;
			parent = parent->_parent;
		}
	}

	return *this;
}

map完整代码

template<typename K, typename V>
struct MapValueOfT
{
	const K& operator()(const pair<K, V>& kv) const
	{
		return kv.first;
	}
};

template<typename K, typename V> 
class map
{
public:
	typedef pair<K, V> valueType;
	typedef RBTree<K, valueType, MapValueOfT<K, V>> Tree;
	typedef typename RBTree<K, valueType, MapValueOfT<K, V>>::iterator iterator;

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

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



	pair<iterator, bool> insert(const pair<K, V>& kv)
	{
		return _t.Insert(kv);
	}

	void inorder()
	{
		_t.InOrder();
	}

	V& operator[](const K& key)
	{
		return (insert(make_pair(key, V())).first)->second;
	}

	Tree _t;
};

set完整代码

template<typename K>
struct SetValueOfT
{
	const K& operator()(const K& key) const
	{
		return key;
	}
};

template<typename K>
class set
{
public:
	typedef K valueType;
	typedef RBTree<K, valueType, SetValueOfT<K>> Tree;
	typedef typename RBTree<K, valueType, SetValueOfT<K>>::iterator iterator;

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

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


	pair<iterator, bool> insert(const K& key)
	{
		return _t.Insert(key);
	}

	void inorder()
	{
		_t.InOrder();
	}

	Tree _t;
};

改造后的红黑树代码

enum Color
{
	BLACK,
	RED
};
template<typename T>
struct RBNode
{
	RBNode(const T& data)
		: _data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(RED)
	{}

	RBNode<T>* _left;
	RBNode<T>* _right;
	RBNode<T>* _parent;
	Color _col;
	T _data;
};

template<typename T, typename Ref, typename Ptr>
class Iterator
{
public:
	typedef RBNode<T> Node;
	typedef Iterator<T, Ref, Ptr> Self;

	Iterator(Node* node)
		:_node(node)
	{}

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

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

	T& operator*()
	{
		return _node->_data;	
	}

	Ptr operator->()
	{
		return &(_node->_data);
	}

	Self& operator++()
	{
		// 右子树不为空,就是找右子树中的最左节点
		if (_node->_right)
		{
			_node = _node->_right;
			while (_node->_left)
			{
				_node = _node->_left;
			}

		}
		else
		{
			// 右子树为空,找孩子不是父亲的右节点的父节点
			Node* parent = _node->_parent;
			while (parent && parent->_right == _node)
			{
				_node = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}

		return *this;
	}

	Self& operator--()
	{
		// 左子树不为空,找左子树中的最右节点
		if (_node->_left)
		{
			_node = _node->_left;
			while (_node && _node->_left)
			{
				_node = _node->_left;
			}
		}
		else
		{
			// 左子树为空,找孩子不是父亲的左节点的父节点
			Node* parent = _node->_parent;
			while (parent && parent->_left == _node)
			{
				_node = parent;
				parent = parent->_parent;
			}
		}

		return *this;
	}

	Self operator++(int)
	{
		Self tmp(_node);
		this->operator++();
		return tmp;
	}

	Self operator--(int)
	{
		Self tmp(_node);
		operator--();
		return tmp;
	}

private:
	Node* _node;
};

template<typename Key, typename Value, typename ValueOfT = less<Key>>
class RBTree
{
public:
	typedef RBNode<Value> Node;
	typedef Iterator<Value, Value&, Value*> iterator;

	RBTree()
		: _root(nullptr)
	{}

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

		return iterator(cur);
	}

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



	pair<iterator, bool> Insert(const Value& data)
	{
		// 空树的插入
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(_root, true);
		} 

		// 非空树的插入
		Node* parent = nullptr;
		Node* cur = _root;

		// 寻找插入的位置
		while (cur)
		{
			parent = cur;

			if (cmp(data) > cmp(cur->_data))
			{
				cur = cur->_right;
			}
			else if (cmp(data) < cmp(cur->_data))
			{
				cur = cur->_left;
			}
			else	// 找到重复元素,插入失败
			{
				return make_pair(cur, false);
			}
		}

		// 开始插入
		cur = new Node(data);
		if (cmp(data) > cmp(parent->_data))
		{
			cur->_parent = parent;
			parent->_right = cur;
		}
		else
		{
			cur->_parent = parent;
			parent->_left = cur;
		}
		Node* newNode = cur;

		// 如果父节点是根节点,那么它的颜色一定是要黑色,不然在前面插入的时候已经出错了
		// 所以进入循环,就说明一定存在祖父节点
		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;
				}
				else	// 叔叔不存在或者叔叔为黑
				{
					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);
						RotateLR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
						

					break;
				}
			}
			else if (parent == grandfather->_right)
			{
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)	// 叔叔存在且为红,继续往上更新
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					cur = grandfather;
				}
				else	// 叔叔不存在或者叔叔为黑
				{
					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);
						RotateRL(grandfather);
						cur->_col =	 BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;

		return make_pair(newNode, true);
	}


	void InOrder()
	{
		_InOrder(_root);
	}

	// 根据黑色节点数量判断是否满足红黑树条件
	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			puts("root的颜色为红!!!");
			return false;
		}

		int balanceNum = 0;
		return Check(_root, balanceNum, 0);	
	}


private:
	// 前序遍历检查每天路径上的黑色节点数量
	bool Check(Node* root, int& balanceNum, int blackNum)
	{
		if (root == nullptr)
		{
			if (balanceNum == 0)
			{
				balanceNum = blackNum;
				return true;
			}
			else
			{
				if (blackNum == balanceNum)
					return true;
				else 
					return false;
			}
		}

		if (root->_col == BLACK)
		{
			blackNum++;
		}

		return Check(root->_left, balanceNum, blackNum)
			&& Check(root->_right, balanceNum, blackNum);
	}


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

		_InOrder(root->_left);
		cout << root->_data.first << " : " << root->_data.second << endl;
		_InOrder(root->_right);
	}

	// 左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* pparent = parent->_parent;

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

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

		subR->_parent = pparent;
		if (pparent)
		{
			if (pparent->_left == parent)
				pparent->_left = subR;
			else
				pparent->_right = subR;
		}
		else
			_root = subR;


	}

	// 右单旋
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* pparent = parent->_parent;


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

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

		subL->_parent = pparent;
		if (pparent)
		{
			if (pparent->_left == parent)
				pparent->_left = subL;
			else
				pparent->_right = subL;
		}
		else
			_root = subL;


	}


	// 左右双旋
	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		RotateL(subL);
		RotateR(parent);	
	}

	// 右左双旋
	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		RotateR(subR);
		RotateL(parent);
	}

	ValueOfT cmp;
	Node* _root;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_featherbrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值