C++--红黑树封装实现set和map

发布于:2025-07-14 ⋅ 阅读:(19) ⋅ 点赞:(0)

红黑树封装实现 map 和 set

1. 源码及框架分析

之前在学习 set 和 map 基本使用时就介绍了 set 和 map 底层都是红黑树,但这里有一个问题:set 是K模型的容器,而 map 是KV模型的容器,那它们底层为什么能同样都使用红黑树呢?可以通过阅读源码来解答这个问题。(本文中使用的源码为 SGI 的 stl30 版本)

1.1 头文件分析

//map
#include <stl_tree.h>
#include <stl_map.h>
#include <stl_multimap.h>

//set
#include <stl_tree.h>
#include <stl_set.h>
#include <stl_multiset.h>

可以看到,stl map 和 set 头文件中分别包含了三个头文件,其中 stl_tree.h 是红黑树,stl_map.h 和 stl_set.h 是 map 和 set,而 stl_multimap.h 和 stl_multiset.h 则是 multimap 和 multiset。

这就是为什么使用 multiset 和 multimap 时只需要包 set 和 map 头文件的原因。

1.2 容器成员变量即接口分析

//stl_set.h
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set 
{
public:
 	// typedefs:
 	typedef Key key_type;
 	typedef Key value_type
private:
 	typedef rb_tree<key_type, value_type, 
 					identity<value_type>, key_compare, Alloc> rep_type;
 	rep_type t; // red-black tree representing set
};

//stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc
class map 
{
public:
	// typedefs:
	typedef Key key_type;
	typedef T mapped_type;
	typedef pair<const Key, T> value_type;
private:
	typedef rb_tree<key_type, value_type,
					select1st<value_type>, key_compare, Alloc> rep_type;
	rep_type t; // red-black tree representing map
};

可以看到,set 和 map 的插入删除查找等各种功能都是封装复用的红黑树的接口,对于 set 来说,key_type 也是平时认为的 K,但是发现 set 中居然还有一个变量 value_type,并且 value_type 的类型就是 key_type 的类型,但是 set 不是K模型的容器吗?它里面为什么要设计一个 value_type 变量呢?要解答这个问题,还得阅读红黑树的源码。

而对于 map来说,key_type 就是平常所理解的 K,但是 value_type 却是 pair 类型,它的两个参数分别是模板参数 _Key 和 _Tp,也就是正常认为的传递给 map 的 K 和 V。

1.3 有关基类红黑树的分析

// stl_tree.h
//红黑树基类
struct __rb_tree_node_base
{
 	typedef __rb_tree_color_type color_type;
 	typedef __rb_tree_node_base* base_ptr;
    
 	color_type color; 
 	base_ptr parent;
 	base_ptr left;
 	base_ptr right;
};

//红黑树的节点结构
template<typename Value>
struct _rb_tree_node : public _rb_tree_node_base
{
	typedef rb_tree_node<_Val>* _link_type;
    Value value_field;
};

//红黑树
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc= alloc
class rb_tree 
{
protected:
 	typedef void* void_pointer;
 	typedef __rb_tree_node_base* base_ptr;
 	typedef __rb_tree_node<Value> rb_tree_node;
 	typedef rb_tree_node* link_type;
 	typedef Key key_type;
	typedef Value value_type;
public:
 	// insert⽤的是第⼆个模板参数左形参 
 	pair<iterator,bool> insert_unique(const value_type& x);
 
 	// erase和find⽤第⼀个模板参数做形参 
 	size_type erase(const key_type& x);
 	iterator find(const key_type& x);

protected:
 	size_type node_count; // keeps track of size of tree
	link_type header;
};

可以看到,红黑树中定义了一个基类 _rb_tree_node_base,基类中定义了节点的颜色和三叉链结构,然后让 _rb_tree_node 去继承基类,并在类中增加成员变量 value_field,value_field 的类型是 Value,而这个 Value 恰好是红黑树的第二个模板参数,也就是 map 和 set 传递过来的 value_type,如下:

在这里插入图片描述

通过上图对框架的分析,可以看到源码中 rb_tree 用了一个巧妙的泛型思想实现,rb_tree 是实现 key 的搜索场景,还是 key/value 的搜索场景不是直接写死的,而是由第二个模板参数 Value 决定 _rb_tree_node 中存储的数据类型。

  • set 实例化 rb_tree 时第二个模板参数给的是 Key
  • map 实例化 rb_tree 时第二个模板参数给的是 pair<const Key, T>

这样一颗红黑树既可以实现 key 搜索场景的 set,也可以实现 key/value 搜索场景的 map

补充:

要注意,源码里面模板参数用 T 代表 value,而内部写的 value_type 并不日常 key/value 场景中说的 value,源码中的 value_type 反而是红黑树节点中存储的真实数据的类型。

这里源码的命名风格比较乱,set 模版参数用的 Key 命名,map 用的是 Key 和 T 命名,而 rb_tree 用的又是 Key 和 Value。

问题:

rb_tree 第二个模板参数 Value 已经控制了红黑树节点中存储的数据类型,为什么还要传第一个模板参数 Key 呢?尤其是 set,两个模板参数是一样的。

要注意的是对于 map 和 set,实现 find/erase 时的函数参数都是Key,所以第一个模板参数是传给 find/erase 等函数做形参的类型。对于 set 而言两个参数是一样的,但是对于 map 而言就完全不一样了,map insert的是pair对象,但是 find 和 erase 的是 Key 对象。

2. 模拟实现map和set

2.1 实现复用红黑树框架

参考源码框架,map 和 set 复用之前实现的红黑树,并且对比源码进行一些调整,Key 的参数用 K ,Value 的参数就用 V ,红黑树中的数据类型就用 T。

// RBTree.h
enum Colour

{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode
{
	T _data;
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Colour _col;
	RBTreeNode(const T& data)
		: _data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
	{}
};

template<class K, class T, class KeyOfT>
class RBTree
{
private:
	typedef RBTreeNode<T> Node;
	Node* _root = nullptr;
    
public:
	//...
}

// Myset.h
namespace tcq
{
	template<class K>
	class set
	{
        //...
	};
}


// Mymap.h
namespace tcq
{
	template<class K, class V>
	class map
	{
		//...
	};
}

补充:

自行模拟实现的 map 和 set 使用命名空间分隔开,避免和标准库中的 map 和 set 形成冲突。

2.2 模拟实现insert

因为 RBTree 实现了泛型,不知道 T 参数是 K,还是 pair<K, V>,那么 insert 内部进行插入逻辑比较时,就没办法进行比较,因为 pair 的默认支持的是 key 和 value 一起参与比较,而需要的任何时候只比较 key,所以在 map 和 set 层分别实现一个 MapKeyOfTSetKeyOfT 的仿函数传给 RBTree 的第三个参数 KeyOfT,然后 RBTree 中通过 KeyOfT 仿函数取出 T 类型对象中的 key,再进行比较,即可实现 insert 的功能,具体细节参考如下代码实现。

// 源码中pair⽀持的<重载实现>
template <class T1, class T2>
bool operator< (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs)
{ 
    return lhs.first<rhs.first || (!(rhs.first<lhs.first) && 
lhs.second<rhs.second); 
}
// Myset.h
namespace tcq
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
        
	public:
		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
        
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}
// Mymap.h
namespace bit
{
	template<class K, class V>
	class map

	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		bool insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};
}
//RBTree.h
//map: RBTree<K, pair<K,V>, MapKeyOfT> _t;
//set: RBTree<K, K, SetKeyOfT> _t;
template<class K, class T, class KeyOfT>
class RBTree
{
private:
	typedef RBTreeNode<T> Node;
	Node* _root = nullptr;
public:
	bool Insert(const T& data)
	{
        //判断根节点是否为空
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;//根节点的颜色一定为黑
			return true;
		}
        
        //寻找插入位置
		KeyOfT kot; //仿函数对象
		Node* parent = nullptr;
		Node* cur = _root;
		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 false;//不允许重复节点
			}
		}
        
        //走到空开始插入,注意这里还需要修改父节点的指向
		//新增节点的颜色为默认被初始化为红色,所以这里不需要再显式赋值
		cur = new Node(data);
		Node* newnode = cur;
		// 新增结点,颜⾊给红⾊ 
		cur->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;//修改父节点指向
        
		//调整结点...
		return true;
	}
}

2.3 模拟实现底层红黑树

2.3.1 红黑树的迭代器

iterator 实现的大框架跟 list 的 iterator 思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为,比如 operator*() 返回节点中的数据,operator->() 返回节点的地址,operator!=() 比较两个迭代器是否相等,其中,为了满足 const 迭代器返回 const T& 和 const T*,需要增加两个模板参数 Ref 和 Ptr。

//红黑树的迭代器
//__RBTreeIterator<T, T&, T*>  			   //普通迭代器
//__RBTreeIterator<T, const T&, const T*>  //const迭代器
template<class T, class Ref, class Ptr>
struct __RBTreeIterator 
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;

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

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

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

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

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

以上要求在模拟实现list 的时候都已经详细介绍过了所以这里不再赘述。红黑树的迭代器和 list 迭代器不同的地方在于红黑树 end() 迭代器的位置以及迭代器如何进行 ++ 与 –

2.3.1.1 迭代器的++与–

迭代器 – 的实现跟 ++ 的思路完全类似,逻辑正好反过来即可,因为它访问顺序是右子树->根结点->左子树,所以下面重点对 ++ 进行详细介绍。迭代器++的核心逻辑就是不看全局,只看局部,只考虑当前中序局部要访问的下一个结点。

  • **情况一:**迭代器++时,如果 it 指向的结点的右子树不为空,代表当前结点已经访问完了,要访问下一个结点是右子树的中序第一个;一棵树中序第一个是最左结点,所以直接找右子树的最左结点即可。
  • **情况2:**迭代器++时,如果 it 指向的结点的右子树为空,代表当前结点已经访问完了且当前结点所在的子树也访问完了,要访问的下一个结点在当前结点的祖先里面,所以要沿着当前结点到根的祖先路径向上找。

示例分析:

img

如果当前结点是父亲的左,根据中序左子树->根结点->右子树,那么下一个访问的结点就是当前结点的父亲;如上图:it指向15,15右为空,15是17的左,所以下一个访问的结点就是17。

如果当前结点是父亲的右,根据中序左子树->根结点->右子树,当前结点所在的子树访问完了,当前结点所在父亲的子树也访问完了,那么下一个访问的需要继续往根的祖先中去找,直到找到孩子是父亲左的那个祖先(目标节点的左孩子是当前节点的父亲)就是中序要访问的下一个结点。如图:it指向11,11右为空,11是8的右,11所在子树访问完了,8所在子树也访问完了,继续往上找,8是13的左,那么下一个访问的结点就是13。

代码实现:

// RBTree.h
//红黑树的迭代器
//__RBTreeIterator<T, T&, T*>  				//普通迭代器
//__RBTreeIterator<T, const T&, const T*>  	//const迭代器
template<class T, class Ref, class Ptr>
struct __RBTreeIterator 
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;

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

	//++迭代器
	Self& operator++() 
    {
		//如果右子树不为空,则++迭代器为右子树的最左节点
		if (_node->_right) 
        {
			Node* cur = _node->_right;
			while (cur->_left)
				cur = cur->_left;
			_node = cur;
		}
		//如果右子树为空,则++迭代器为 cur为父节点的左孩子的那一个祖先节点
		else 
        {
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur != parent->_left) 
            {
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}

		return *this;
	}

	//迭代器++
	Self& operator++(int) 
    {
		Self& tmp = *this;
		operator++();
		return tmp;
	}

	//--迭代器
	Self& operator--() 
    {
		//如果左子树存在,则--迭代器为左子树的最右节点
		if (_node->_left) 
        {
			Node* cur = _node->_left;
			while (cur->_right)
				cur = cur->_right;
			_node = cur;
		}
		//如果左子树为空,则--迭代器为 cur为父节点的右孩子的那一个祖先节点
		else 
        {
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right != cur) 
            {
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}

		return *this;
	}

	//迭代器--
	Self& operator--(int) 
    {
		Self& tmp = *this;
		operator--();
		return tmp;
	}
};
2.3.1.2 end() 迭代器的位置

STL 明确规定,begin() 与 end() 代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,可以得到一个有序的序列,因此,begin() 可以放在红黑树中最小节点 (即最左侧节点) 的位置,end() 可以放在最大节点 (最右侧节点) 的下一个位置。为了让 end() 能够指向最右节点的下一个节点, stl 源码中增加了一个哨兵位的头结点,该节点的 left 指向这棵树的最左节点,也就是 begin(),right 指向这棵树的最右节点,parent 指向 nullptr,然后让根的父节点指向它,最右节点的 right 也指向它,所以在 stl 源码的实现中这个哨兵位头结点就是 end()。

在这里插入图片描述

在这里插入图片描述

如上图:当 it 指向 50 时,执行 ++it,50 是 40 的右子节点,40 是 30 的右子节点,30 是 18 的右子节点,18 到根没有父亲,也没有找到“孩子是父亲左子节点”的那个祖先,此时父亲为空,就将 it 中的节点指针置为 nullptr,用 nullptr 去充当 end()

// RBTree.h
template<class K, class T, class KeyOfT>
class RBTree 
{
	typedef RBTreeNode<T> Node;
public:
    //迭代器
    typedef __RBTreeIterator<T, T&, T*> iterator;
	typedef __RBTreeIterator<T, const T&, const T*> const_iterator;
    
    //begin是树的最左节点
    iterator begin() 
    {
        if (_root == nullptr)
            return iterator(nullptr);

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

        return iterator(left);
    }
    
    const_iterator begin() const 
    {
        if (_root == nullptr)
            return const_iterator(nullptr);

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

        return const_iterator(left);
    }

    //end定义为空
    iterator end() 
    {
        return iterator(nullptr);
    }

    const_iterator end() const 
    {
        return const_iterator(nullptr);
    }
};

以上所介绍的都是 set 和 map 底层红黑树的迭代器的设计,对于 set 和 map 的迭代器还有一下其他的要求。具体介绍在下面模拟实现 set 和 map 中介绍。

2.3.2 完整代码(RBtree.h)
// RBtree.h
enum Colour
{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode
{
	T _data;
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Colour _col;
	RBTreeNode(const T& data)
		: _data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
	{}
};

template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr> Self;

	Node* _node;
	Node* _root;

	RBTreeIterator(Node* node, Node* root)
		:_node(node)
		, _root(root)
	{}

	Self& operator++()
	{
		if (_node->_right)
		{
			// 右不为空,右⼦树最左结点就是中序第⼀个 
			Node* leftMost = _node->_right;
			while (leftMost->_left)
			{
				leftMost = leftMost->_left;
			}

			_node = leftMost;
		}
		else

		{
			// 孩⼦是⽗亲左的那个祖先 
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right) 
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self& operator--()
	{
		if (_node == nullptr) // end()

		{
			// --end(),特殊处理,⾛到中序最后⼀个结点,整棵树的最右结点 
			Node* rightMost = _root;
			while (rightMost && rightMost->_right)
			{
				rightMost = rightMost->_right;
			}

			_node = rightMost;
		}
		else if (_node->_left)
		{
			// 左⼦树不为空,中序左⼦树最后⼀个 
			Node* rightMost = _node->_left;
			while (rightMost->_right)
			{
				rightMost = rightMost->_right;
			}

			_node = rightMost;
		}
		else
		{
			// 孩⼦是⽗亲右的那个祖先 
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = cur->_parent;
			}

			_node = parent;
		}
		return *this;
	}

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

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

	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 KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;

public:
	typedef RBTreeIterator<T, T&, T*> Iterator;
	typedef RBTreeIterator<T, const T&, const T*> ConstIterator;

	Iterator Begin()
	{
		Node* leftMost = _root;
		while (leftMost && leftMost->_left)
		{
			leftMost = leftMost->_left;
		}
		return Iterator(leftMost, _root);
	}

	Iterator End()
	{
		return Iterator(nullptr, _root);
	}

	ConstIterator Begin() const

	{
		Node* leftMost = _root;
		while (leftMost && leftMost->_left)
		{
			leftMost = leftMost->_left;
		}
		return ConstIterator(leftMost, _root);
	}

	ConstIterator End() const
	{
		return ConstIterator(nullptr, _root);
	}

	RBTree() = default;

	~RBTree()
	{
		Destroy(_root);
		_root = nullptr;
	}

	pair<Iterator, bool> Insert(const T & data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(Iterator(_root, _root), true);
		}

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

		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, _root), false);
			}
		}

		cur = new Node(data);
		Node* newnode = cur;

		// 新增结点。颜⾊红⾊给红⾊ 
		cur->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			parent->_right = cur;
		}
		else

		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			// g
			// p u
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_col == RED)
				{
					// u存在且为红 -》变⾊再继续往上处理 
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					// u存在且为⿊或不存在 -》旋转+变⾊ 
					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);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else
			{
				// g
				// u p
				Node* uncle = grandfather->_left;
				// 叔叔存在且为红,-》变⾊即可 
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					// 继续往上处理 
					cur = grandfather;
					parent = cur->_parent;
				}
				else // 叔叔不存在,或者存在且为⿊ 
				{
					// 情况⼆:叔叔不存在或者存在且为⿊ 
					// 旋转+变⾊ 
					// g
					// u p
					//	  c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//  g
						// u p
						//  c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}
		_root->_col = BLACK;

		return make_pair(Iterator(newnode, _root), true);
 }

 Iterator Find(const K& key)
 {
	 Node* cur = _root;
	 while (cur)
	 {
		 if (cur->_kv.first < key)
		 {
			 cur = cur->_right;
		 }
		 else if (cur->_kv.first > key)
		 {
			 cur = cur->_left;
		 }
		 else
		 {
			 return Iterator(cur, _root);
		 }
	 }
	 return End();
 }

 private:
	 void RotateL(Node* parent)
	 {
		 Node* subR = parent->_right;
		 Node* subRL = subR->_left;

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

		 Node* parentParent = parent->_parent;

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

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

	 void RotateR(Node* parent)
	 {
		 Node* subL = parent->_left;
		 Node* subLR = subL->_right;
		 parent->_left = subLR;
		 if (subLR)
			 subLR->_parent = parent;
		 Node* parentParent = parent->_parent; 
		 subL->_right = parent;
		 parent->_parent = subL;

		 if (parentParent == nullptr)
		 {
			 _root = subL;
			 subL->_parent = nullptr;
		 }
		 else
		 {
			 if (parent == parentParent->_left)
			 {
				 parentParent->_left = subL;
			 }
			 else

			 {
				 parentParent->_right = subL;
			 }
			 subL->_parent = parentParent;
		 }
	 }

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

		 Destroy(root->_left);
		 Destroy(root->_right);
		 delete root;
	 }

private:
	Node* _root = nullptr;
};

2.4 模拟实现map中的[]

map 要支持 [] 主要需要修改 insert 返回值支持,修改 RBTree 中的 insert 返回值为 pair<Iterator, bool> Insert(const T& data)

// RBTree.h
//修改后的插入
pair<Iterator, bool> Insert(const T& data)
{
    // 判断根节点是否为空
    if (_root == nullptr) 
    {
        _root = new Node(kv);
        _root->_col = BLACK;  // 根节点的颜色一定为黑
        return make_pair(Iterator(_root, _root), true);
    }

    // 寻找插入位置
    KeyOfT kot
    Node* parent = nullptr;
    Node* cur = _root;
    while (cur) 
    {
        if (kot(cur->_data) > kot(data)) 
        {
            parent = cur;
            cur = cur->_left;
        }
        else if (kot(cur->_data) < kot(data)) 
        {
            parent = cur;
            cur = cur->_right;
        }
        else 
        {
            return return make_pair(Iterator(cur, _root), false);  // 不允许重复节点
        }
    }

    // 走到空开始插入,注意这里还需要修改父节点的指向
    // 新增节点的颜色为默认被初始化为红色,所以这里不需要再显式赋值
    cur = new Node(data);
    Node* newnode = cur;
	cur->_col = RED;

    if (kot(parent->_data) > kot(data))
        parent->_left = cur;
    else
        parent->_right = newNode;
    cur->_parent = parent;  // 修改父节点指向

    // 如果父节点颜色为红色,则需要进行调整
    while(parent && parent->_col == RED)
    {
        Node* grandfather = parent->_parent;
    	// 红黑树的调整
		//	g
		// p u
		// 父节点在组父节点左边
		if (parent == grandfather->_left)
		{
			Node* uncle = grandfather->_right;
            // 第一种调整情况:叔叔存在且为红
			if (uncle && uncle->_col == RED)
			{
				// u存在且为红 ->变⾊再继续往上处理 
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;
				cur = grandfather;
				parent = cur->_parent;
			}
            // 第二种调整情况:叔叔不存在或叔叔存在且为黑
            else
			{
				// u存在且为黑或不存在 -> 旋转+变⾊ 
				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);

					cur->_col = BLACK;
					grandfather->_col = RED;
				}
                
                break;
			}
		}
        //	g
		// u p
		// 父节点在组父节点右边
		else
		{
			Node* uncle = grandfather->_left;
			// 第一种调整情况:叔叔存在且为红
			if (uncle && uncle->_col == RED)
			{
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;
                
				// 继续往上处理 
				cur = grandfather;
				parent = cur->_parent;
			}
            // 第二种调整情况:叔叔不存在或叔叔存在且为黑
			else
			{
				// u存在且为黑或不存在 -> 旋转+变⾊ 
				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);

					cur->_col = BLACK;
					grandfather->_col = RED;
				}
                break;
			}
		}
    }
    
    _root->_col = BLACK;
    
 	return make_pair(Iterator(newnode, _root), true);
}

// Mymap.h
V& operator[](const K& key)
{
 	pair<iterator, bool> ret = insert(make_pair(key, V()));
 	return ret.first->second;
}

2.5 模拟实现set

set 模拟实现的前面部分很简单,在类中定义一个 RBTree 类型的成员变量,然后插入、查找等函数都直接调用红黑树的对应函数即可。set 模拟实现的重难点在于 set 迭代器的实现,set的iterator也不支持修改,把set的第二个模板参数改成const K即可, 如下:

//使用红黑树的const迭代器来封装set的普通迭代器
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
2.5.1 完整代码(Myset.h)
// Myset.h
#include"RBTree.h"
namespace tcq
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};

	public:
		typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;
		typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;

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

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

		const_iterator begin() const
		{
			return _t.Begin();
		}

		const_iterator end() const

		{
			return _t.End();
		}

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

		iterator find(const K& key)
		{
			return _t.Find(key);
		}

	private:
		RBTree<K, const K, SetKeyOfT> _t;
	};
}

2.6 模拟实现map

map 和 set 一样,模拟实现的前面部分很简单如插入、查找都直接复用红黑树的相应函数实现;不同的是,map 是 KV模型 的容器, KV模型 的 key 虽然也不允许修改,因为这可能会破坏搜索树的结构,但是 value 是运行修改的,所以 map 的普通迭代器封装红黑树的普通迭代器即可,而不用将其封装为红黑树的 const 迭代器。

同时,也不用担心 map 的 key 被修改的问题,因为 map 在定义红黑树的成员变量时传递给红黑树的 T 模板参数为 pair<const K, V>,它保证了 map 的 key 值不能被修改

typedef typename RBTree<K, std::pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, std::pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

//const K保证了map的key不会被修改
RBTree<K, std::pair<const K, V>, MapKeyOfT> _t;

map 模拟实现的难点在于 operator[](const K& key) 函数的实现前文已经对此内容进行了介绍这里就不过多赘述。

2.6.1 完整代码(Mymap.h)
// Mymap.h
#include"RBTree.h"
namespace bit
{
	template<class K, class V>
	class map
	{
		struct MapKeyOfT

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

	public:
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;

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

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

		const_iterator begin() const

		{
			return _t.Begin();
		}

		const_iterator end() const

		{
			return _t.End();
		}

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

		iterator find(const K& key)
		{
			return _t.Find(key);
		}

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

	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}

网站公告

今日签到

点亮在社区的每一天
去签到