中级C++:红黑树:map和set的迷你实现

本文详细介绍了如何使用C++实现红黑树,并将其封装为map和set容器。通过模板类RBTree,实现了红黑树的基本操作,包括迭代器的实现,以及针对set和map的不同需求进行的定制。文中还展示了如何利用仿函数KeyOfT来处理不同类型的查找和插入操作。
摘要由CSDN通过智能技术生成

基建改造

template<class K, class T,class KeyofT>
	class RBTree
	{
	//类域中重命名 typedef 如果想让类外面用到,就加public修饰。
		....
	}
  • 为了兼容set和map,对于第一个参数我们是用来比较的key类型,第二个参数是用来储存数据的类型
  • 由于set使用的是K。map使用的K是pair<k,v>中的first;红黑树这个类模板,也不知道这个类型到底具体是什么,所以再增加一个仿函数类型模板参数,获取K的类型。
template<class T>
struct RBTreeNode
{
	RBTreeNode* _left;
	RBTreeNode* _right;
	RBTreeNode* _parent;
	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)
	{
	}
	
};

在这里插入图片描述


红黑树的迭代器

用一个节点的指针初始化成迭代器,实现对STL所有容器进行统一方式的访问。

  • T,T&,T*iterator要确保和官方迭代器名字一致就可以用范围for。
    • *it(迭代器),拿到这个指针里面的数据。
    • != 就是两个节点的指针不相等
  • 红黑树的++:访问到容器的下一个节点:
  • 红黑树的 begin 则应该是中序里最左边的一个节点。
    • ++,看begin 的右侧,有的话,找右子树里面最左面的一个。
    • 若右侧也没有:代表我这一层的左子树右子树访问结束。返回上一层。
    • 由于这一层是从上一层的左子树下来的,要看当前节点是不是双亲结点的左侧;
      • 不是则一直迭代往上走;
      • 是就返回双亲结点。
        在这里插入图片描述
        在这里插入图片描述
template<class T, class Ref, class Ptr>
struct RBTreeiterator   
{
	typedef RBTreeNode<T> Node;...
	typedef RBTreeiterator<T, Ref, Ptr> Self;  
	Node* _node;

	RBTreeiterator(Node* node = nullptr)
		:_node(node)
	{
	}

	//*it 对一个指针解引用,取到的是节点里面的数据
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}

	//红黑树迭代器的前置++ 返回是自增以后的迭代器
	Self& operator++()
	{
		if (_node->_right)
		{
			//右边存在,找右子树最左边的那个节点
			Node* subRL = _node->_right;
			//左子树到头了,此刻的subRL就是右子树里最左边的节点
			while (subRL->_left)
			{
				subRL = subRL->_left;
			}
			_node = subRL;
		}
		else//代表当前这个子树访问完了,左 中 右 找此根的父亲,该父亲的左孩子是此根。
		{
			Node* cur = _node;
			Node* parent = _node->_parent;
			while (parent&& parent->_right==cur)
			{
				cur = parent;
				parent = cur->_parent;
			}

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

封装成map

  • 有了第二个模板参数,为什么还要第一个模板参数K呢;因为查找是按K值查找的…
  • 迭代器和插入用的都是红黑树的。参考官方文档可知:插入返回的时pair类型,第一个参数是插入结点或值相等结点的迭代器和布尔值。
  • 还有一个 [ ] 重载,返回的时pair<k,v>里面V的引用。make_pair(“呵呵哒”,“我C”)–“我C”
  • typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;告诉编译器那一长托是个类型,不然编不过去。
template < class K, class V>
	class map
	{
		struct MapKeyOfT //把 K 提取出来
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;

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

		iterator end()
		{
			return _t.end();
		}
//iterator --》 结点的数据类型
		pair<iterator, bool> insert(const pair<const K, V>& kv)
		{
			return _t.Insert(kv);
		}

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
			return ret.first->second;// iterator.operator->() data:pair<k,v>的地址  -> second   
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;//使用模板显式的声明使用的类型
	};

红黑树的改造

  • T:set:int,char…;map:pair<int,int>…
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node; ....//T类型的节点
public:
	typedef RBTreeIterator<T, T&, T*> iterator;  .....
	typedef RBTreeIterator<T, const T&, const T*> const_iterator;

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

		//return left;
		return iterator(left);
	}

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

	RBTree()
		:_root(nullptr)
	{}
	....
	Node* Find(const K& key);
	//插入
	pair<iterator, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
				......
			return make_pair(iterator(_root), true);
		}

		Node* parent = nullptr;
		Node* cur = _root;

		KeyOfT kot;  			//仿函数使用场景   
		while (cur)
		{
			.......
			if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return make_pair(iterator(cur), false);
			}
		}

		// 新增节点,颜色是红色,可能破坏规则3,产生连续红色节点
		cur = new Node(data);
		Node* newnode = cur;   //便于返回迭代器...
		cur->_col = RED;
		........
		_root->_col = BLACK;
		return make_pair(iterator(newnode), true);
	}

封装成set

  • 第二个模板参数也传K…
template < class K>
	class set
	{
		struct SetKeyOfT  
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;

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

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

		pair<iterator, bool> insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
----//仿函数使用场景..
		KeyOfT kot;
		while (cur)
		{
			if (kot(cur->_data) < kot(data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
....

高赞文章:C++红黑树模拟实现map和set

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值