【C++】set map模拟实现

本文详细介绍了红黑树在map和set中的应用,重点讨论了如何通过RBTreeNode结构实现插入操作,以及set和map如何利用红黑树的迭代器进行上层封装。作者还提到了红黑树的颜色属性和旋转操作在保持平衡性中的关键作用。
摘要由CSDN通过智能技术生成

模拟实现

红黑树

map和set底层都是使用的红黑树,但是上层的接口有一些不同。像map的话是靠key获得value,而set因为key和value是相同的,所以涉及到value的操作全都等同于key,比如find。所以需要对红黑树加一层封装。红黑树用的是上篇的代码:

namespace mystd {
	enum Color
	{
		BLACK,
		RED
	};

	template<class K, class V>
	struct RBTreeNode
	{
		RBTreeNode<K, V>* _parent;
		RBTreeNode<K, V>* _left;
		RBTreeNode<K, V>* _right;

		pair<K, V> _kv;
		Color _col;

		RBTreeNode(const pair<K, V>& kv)
			:_left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
			, _kv(kv)
			, _col(RED)
		{}
	};

	template<class K, class V>
	class RBTree
	{
		typedef RBTreeNode<K, V> Node;
	public:
		bool Insert(const pair<K, V>& kv)
		{
			if (_root == nullptr)
			{
				_root->_kv = kv;
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (kv.first < cur->_kv.first)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (kv.first > cur->_kv.first)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					return false;
				}
			}

			cur = new Node(kv);
			cur->_col = RED;
			// 处理颜色
			if (parent->_kv.first < kv.first)
			{
				parent->_right = cur;
				cur->_parent = parent;
			}
			else if (parent->_kv.first > kv.first)
			{
				parent->_left = cur;
				cur->_parent = parent;
			}

			while (parent && parent->_col == RED)
			{
				Node* grandfather = parent->_parent;
				// 叔叔节点存在
				if (parent == grandfather->_left)
				{
					Node* uncle = grandfather->_right;
					// LL or RR的上溢情况
					if (uncle && uncle->_col == RED)
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandfather->_col = RED;

						// 递归上溢
						cur = grandfather;
						parent = cur->_parent;
					}
					else//叔父节点不存在
					{
						if (cur = parent->_left)//LL,右旋,参考AVL树
						{
							RorateR(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else//LR, cur变成grandfather,father变成left,grandfather变成right
						{
							RotateR(parent);
							RotateL(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}

						break;//234树只有2个节点,不可能存在上滤情况,break;
					}
				}
				else // parent = grandfather.right
				{
					Node* uncle = grandfater->_left;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfater->_col = RED;

						cur = grandfater;
						parent = cur->_parent;
					}
					else
					{
						if (cur == parent->_right)
						{
							RotateL(grandfater);
							parent->_col = BLACK;
							grandfater->_col = RED;
						}
						else
						{
							RotateR(parent);
							RotateL(grandfater);
							cur->_col = BLACK;
							grandfater->_col = RED;
						}

						break;
					}
				}
			}
			_root->_col = BLACK;

			return true;
		}

		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 (ppNode == nullptr)
			{
				_root = subL;
				subL->_parent = nullptr;
			}
			else
			{
				if (ppNode->_left == parent)
					ppNode->_left = subL;
				else
					ppNode->_right = subL;

				ppNode->_parent = subL;
			}

			subL->_bf = 0;
			parent->_bf = 0;
		}

		void rotateL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;

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

			Node* ppNode = parent->_parent;
			parent->_parent = subR;
			subR->_left = parent;

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

				subR->_parent = ppNode;
			}

			parent->_bf = 0;
			subR->_bf = 0;
		}
	private:
		Node* _root = nullptr;
	};
}

set

set的迭代器调用的是RBTree的迭代器,RBTree的迭代器设计思路主要是一个基础node,在基础node上封装一层普通node,可以用继承来实现。然后定义基础的iterator_node,将普通红黑树node传进来,并实现 increment()和decrement()两个基础的,内部逻辑是 ++ 和 – ;
increment:

  1. 检测右孩子是否存在
    1. 存在,则获得右子树的最左下节点
    2. 不存在,获得父节点的右子树
      1. 若父节点右子树是自身,重复上一步
      2. 若不是自身,获得父节点
        有一点抽象,大家可以去看set map源码阅读里红黑树那一小节的图;decrement同理。

将底层的迭代器node封装成正常的迭代器node,再实现begin():一路左下递归,end():一路右下递归等迭代器访问内容。下面set假设rbtree迭代器存在。

#include "RBTree.h"

namespace mystd
{
	template<class K>
	class set
	{
	public:
		typedef typename RBTree<K, K>::iterator iterator;

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

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

		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K> _t;
	};
}


map

#include "RBTree.h"

namespace mystd
{
	template<class K, class V>
	class map 
	{
	public:
		typedef typename RBTree<K, V>::iterator iterator;

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

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

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


结束语

set map主要都是调用红黑树的迭代器,所以最好还是看看源码中红黑树的迭代器的设计思想

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值