STL 源码解剖系列:map/set 的底层复用与红黑树封装

1.源码及框架分析

SGI-STL30版本源代码,map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等⼏个头⽂件中。
map和set的实现结构框架核⼼部分截取出来如下:

1. 节点定义(__rb_tree_node_base 和 __rb_tree_node)

cpp 复制代码
// 基础节点 - 只包含红黑树需要的指针和颜色
struct __rb_tree_node_base
{
    typedef __rb_tree_color_type color_type;  // 颜色类型(通常是bool)
    typedef __rb_tree_node_base* base_ptr;    // 基础指针类型
    
    color_type color;    // 节点颜色(红/黑)
    base_ptr parent;      // 父节点指针
    base_ptr left;        // 左子节点指针
    base_ptr right;       // 右子节点指针
};

// 实际节点 - 继承基础节点,添加值字段
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
    typedef __rb_tree_node<Value>* link_type;
    Value value_field;    // 存储实际的值
                          //set中为Key,map中为pair<const Key,T>
};

2. rb_tree 模板类

cpp 复制代码
template <class Key, class Value, class KeyOfValue, 
          class Compare, class Alloc = alloc>
class rb_tree {
    // ... 成员类型定义
public:
    // 插入:使用 value_type(第二个模板参数)
    pair<iterator,bool> insert_unique(const value_type& x);
    
    // 删除和查找:使用 key_type(第一个模板参数)
    size_type erase(const key_type& x);
    iterator find(const key_type& x);
    
protected:
    size_type node_count;  // 树中节点数量
    link_type header;      // 头节点(特殊节点,简化实现)
};

3. set 的实现

cpp 复制代码
// stl_set.h
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
    // typedefs:
    typedef Key key_type;           // 键类型就是Key
    typedef Key value_type;          // 值类型也是Key,set中元素本身就是key
private:
    // rep_type: 底层红黑树的类型别名
    typedef rb_tree<key_type, value_type,                    // Key, Key
                    identity<value_type>,                     // 从value中提取key的函数对象
                    key_compare,                              // 比较函数类型
                    Alloc> rep_type;                          // 分配器类型
    rep_type t;  // red-black tree representing set
};

4. map 的实现

cpp 复制代码
// 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:
    // rep_type: 底层红黑树的类型别名
    typedef rb_tree<key_type, value_type,                    // Key, pair<const Key,T>
                    select1st<value_type>,                    // 从pair中提取first作为key
                    key_compare,                               // 比较函数类型
                    Alloc> rep_type;                           // 分配器类型
    rep_type t;  // red-black tree representing map
};

5. 函数对象(用于键提取)

cpp 复制代码
// identity: set中使用,直接返回value本身
template <class T>
struct identity : public unary_function<T, T> {
    const T& operator()(const T& x) const { return x; }
};

// select1st: map中使用,返回pair的第一个元素
template <class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type> {
    const typename Pair::first_type& operator()(const Pair& x) const {
        return x.first;
    }
};
  1. 通过对框架的分析,我们可以看到源码中rb_tree⽤了⼀个巧妙的泛型思想实现,rb_tree是实现key的搜索场景,还是key/value的搜索场景不是直接写死的,⽽是由第⼆个模板参数Value决定_rb_tree_node中存储的数据类型。
  2. set实例化rb_tree时第⼆个模板参数给的是key,map实例化rb_tree时第⼆个模板参数给的是pair<const key, T>,这样⼀颗红⿊树既可以实现key搜索场景的set,也可以实现key/value搜索场景的map。
  3. 要注意⼀下,源码⾥⾯模板参数是⽤T代表value,⽽内部写的value_type不是我们我们⽇常key/value场景中说的value,源码中的value_type反⽽是红⿊树结点中存储的真实的数据的类型。
  4. rb_tree第⼆个模板参数Value已经控制了红⿊树结点中存储的数据类型,为什么还要传第⼀个模板参数Key呢?尤其是set,两个模板参数是⼀样的,这是很多同学这时的⼀个疑问。要注意的是对于map和set,find/erase时的函数参数都是Key,所以第⼀个模板参数是传给find/erase等函数做形参的类型的。对于set⽽⾔两个参数是⼀样的,但是对于map⽽⾔就完全不⼀样了,map insert的是pair对象,但是find和ease的是Key对象。

2.模拟实现map和set

2.1实现出复⽤红⿊树的框架,并⽀持insert

  1. 参考源码框架,map和set复⽤之前我们实现的红⿊树。
  2. 我们这⾥相⽐源码调整⼀下,key参数就⽤K,value参数就⽤V,红⿊树中的数据类型,我们使⽤T。
  3. 其次因为RBTree实现了泛型不知道T参数导致是K,还是pair<K, V>,那么insert内部进⾏插⼊逻辑⽐较时,就没办法进⾏⽐较,因为pair的默认⽀持的是key和value⼀起参与⽐较,我们需要时的任何时候只⽐较key,所以我们在map和set层分别实现⼀个MapKeyOfT和SetKeyOfT的仿函数传给RBTree的KeyOfT,然后RBTree中通过KeyOfT仿函数取出T类型对象中的key,再进⾏⽐较,具体细节参考如下代码实现。

2.2⽀持iterator的实现

在STL中,mapset的底层是基于红黑树 实现的。与vector等容器不同,红黑树的内存布局是不连续的,因此不能简单地使用原生指针作为迭代器。我们需要封装节点指针 ,并通过重载运算符来实现迭代器的行为。这里仿照C++list全解析-CSDN博客list迭代器

cpp 复制代码
// 基本框架
template<class T, class Ref, class Ptr>
struct __rb_tree_iterator {
    typedef __rb_tree_node<T>* link_type;
    link_type node;  // 封装的节点指针
    // 重载必要的运算符...
};

中序遍历规则

红黑树迭代器的遍历遵循**中序遍历(Inorder Traversal)**顺序:

  • 左子树 → 根节点 → 右子树

这意味着:

  • begin() 返回的是最左节点(中序第一个节点)

  • 核⼼逻辑就是不看全局,只看局部,只考虑当前中序局部要访问的下⼀个结点。

  • end() 通常用 nullptr哨兵头节点表示(库里面用哨兵)


operator++ 核心实现

迭代器自增(++)的逻辑是找到中序顺序中的下一个节点。这里有两种情况:

  1. 情况二:右子树不为空:如果当前节点有右子树,那么下一个节点就是右子树的最左节点。 (解释:如果it指向的结点的右⼦树不为空,代表当前结点已经访问完了,要访问下⼀个结点是右⼦树的中序第⼀个,⼀棵树中序第⼀个是最左结点=)

  2. 情况二:右子树为空:如果当前节点没有右子树,说明当前节点所在的子树已经访问完毕(左根右),需要向上回溯到祖先节点。 a.如果当前节点是其父节点的左孩子,根据中序左⼦树->根结点->右⼦树,下一个节点就是父节点。b.如果当前节点是其父节点的右孩子,需要继续向上找,直到找到某个节点是其父节点的左孩子,该父节点就是下一个节点--

  • 特殊情况:到达 end()

    当it指向50时,++it时,50是40的右,40是30的右,30是18的右,18 到根没有⽗亲,没有找到孩⼦是⽗亲左的那个祖先,这是⽗亲为空了,那我们就把it中的结点指针置为nullptr,我们⽤nullptr去充当end。 需要注意的是stl源码,空红⿊树增加了⼀个哨兵位头结点做为end(),这哨兵位头结点和根互为⽗亲,左指向最左结点,右指向最右结点。相⽐我们⽤nullptr作为end(),差别不⼤,他能实现的,我们也能实现。只是--end()判断到结点时空,特殊处理⼀下,让迭代器结点指向最右结点。具体参考迭代器--实现。


operator-- 和const迭代器

  1. 迭代器自减(--)的逻辑与自增相反,按照反向中序遍历 :右子树 → 根节点 → 左子树。迭代器--的实现跟++的思路完全类似,逻辑正好反过来即可,因为他访问顺序是右⼦树->根结点->左⼦树,具体参考下⾯代码实现。
  2. set的iterator也不⽀持修改,我们把set的第⼆个模板参数改成const K即可, RBTree<K, const K, SetKeyOfT> _t;
  3. map的iterator不⽀持修改key但是可以修改value,我们把map的第⼆个模板参数pair的第⼀个参数改成const K即可, RBTree<K, pair<const K, V>, MapKeyOfT> _t;
  4. ⽀持完整的迭代器还有很多细节需要修改,具体参考下⾯的代码。

iterator完整实现代码

注意事项:

cpp 复制代码
typedef RBTree<K, K, SetOfT>::Iterator iterator;  // X 编译错误

编译器会报错,原因是:当通过 :: 访问模板类中的成员时,编译器无法区分该成员是类型 还是静态成员变量 。由于 RBTree<K, K, SetOfT> 是一个依赖类型(dependent type),在模板实例化前编译器无法确定 Iterator 的具体性质,因此需要显式使用 typename 关键字声明其为类型。

1.为什么编译错误?

C++ 编译器在处理模板时采用两阶段编译

  • 第一阶段(模板解析阶段) :编译器看到 RBTree<K, K, SetOfT>::Iterator,由于 K 是模板参数,RBTree<K, K, SetOfT> 被称为依赖类型 (dependent type)。此时编译器不知道 Iterator 是:

    • 一个类型(内嵌类型)

    • 还是一个静态成员变量

  • 第二阶段(模板实例化阶段) :当具体类型替换 K 后,编译器才能确定 Iterator 的真实含义。

2.编译器的默认规则

为了能在第一阶段继续编译,编译器采用默认规则:依赖名称被默认识别为值(非类型)

因此,编译器会将 Iterator 当作静态成员变量处理,而忽略它是一个类型的可能性,导致类型定义失败。

3. 什么时候需要 typename?

cpp 复制代码
template<class T,class Ref,class Ptr>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;
	Node* _root;//传一个根节点,支持end()--返回中序的最后一个迭代器
	RBTreeIterator(Node* node,Node*root)
		:_node(node)
		,_root(root)
	{}

	Ptr operator->() 
	{
		return &_node->_data;
	}
	Ref operator*() 
	{
		return _node->_data;
	}
	Self& operator++()
	{
		//右不为空,中序访问的节点就是右树最左节点(最小节点)
		if (_node->_right)
		{
			Node* leftmin = _node->_right;
			
			while (leftmin->_left)
			{
				leftmin = leftmin->_left;
			}
			_node = leftmin;
		}
		else//右为空,访问祖先里面孩子为父亲的左的祖先
		{
			Node* cur = _node;
			Node* parent = _node->_parent;
			while (parent&&parent->_right == cur)//注意当最右节点访问完毕的极端情况
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node= parent;//当it为最后一个元素,最后用nullptr去构造it
		}
		return *this;
	}

	Self& operator--()
	{

		if (_node == nullptr)//支持end()--
		{
			Node* rightmost = _root;
			while (rightmost && rightmost->_right)
			{
				rightmost = rightmost->_right;
			}
			_node = rightmost;
		}

		else if (_node->_left)
		{
			Node* rightmax = _node->_left;
			while(rightmax->_right)
			{
				rightmax = rightmax->_right;
			}
			_node = rightmax;
		}
		else//左子树为空。找孩子是父亲右的父亲
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&&parent->_left==cur)
			{
				cur = parent;
				parent = parent->_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;
	}

};

2.3map的operator[]实现

  1. map要⽀持[]主要需要修改insert返回值⽀持,修改RBtree中的insert返回值为 pair<Iterator, bool> Insert(const T& data)
  2. 有了insert⽀持[]实现就很简单了,具体参考下⾯代码实现

3.封装红黑树模拟实现MyMap&MySet完整代码

RBTree.h

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
#include<vector>
#include<string>

//枚举值表示颜色
enum Color
{
	RED,
	BLACK
};

//默认按key/value结构实现
template<class T>
struct RBTreeNode
{
	// 这⾥更新控制平衡也要加⼊parent指针
	T _data;
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Color _col;
	RBTreeNode(const T& data)
		: _data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(RED)
	{
	}
};
template<class T,class Ref,class Ptr>
struct RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;
	Node* _root;//传一个根节点,支持end()--返回中序的最后一个迭代器
	RBTreeIterator(Node* node,Node*root)
		:_node(node)
		,_root(root)
	{}

	Ptr operator->() 
	{
		return &_node->_data;
	}
	Ref operator*() 
	{
		return _node->_data;
	}
	Self& operator++()
	{
		//右不为空,中序访问的节点就是右树最左节点(最小节点)
		if (_node->_right)
		{
			Node* leftmin = _node->_right;
			
			while (leftmin->_left)
			{
				leftmin = leftmin->_left;
			}
			_node = leftmin;
		}
		else//右为空,访问祖先里面孩子为父亲的左的祖先
		{
			Node* cur = _node;
			Node* parent = _node->_parent;
			while (parent&&parent->_right == cur)//注意当最右节点访问完毕的极端情况
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node= parent;//当it为最后一个元素,最后用nullptr去构造it
		}
		return *this;
	}

	Self& operator--()
	{

		if (_node == nullptr)//支持end()--
		{
			Node* rightmost = _root;
			while (rightmost && rightmost->_right)
			{
				rightmost = rightmost->_right;
			}
			_node = rightmost;
		}

		else if (_node->_left)
		{
			Node* rightmax = _node->_left;
			while(rightmax->_right)
			{
				rightmax = rightmax->_right;
			}
			_node = rightmax;
		}
		else//左子树为空。找孩子是父亲右的父亲
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&&parent->_left==cur)
			{
				cur = parent;
				parent = parent->_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;
	}

};

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;

	Iterator Begin()
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return Iterator(cur,_root);
		//当树为空,也就是_root为空时,cur为空,用空返回迭代器,那么begin()=end()于是空树遍历也没问题
	}

	Iterator End()
	{
		return Iterator(nullptr, _root);//这里用空去做end因为当树为空时,
		//那么cur=root=nullptr,那么begin()=end()于是空树遍历也没问题
	}

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

	Const_Iterator Begin()const
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return Const_Iterator(cur, _root);
	}
	RBTree() = default;

	pair<Iterator,bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root=new Node(data);
			_root->_col = BLACK;//根节点为黑色
			//return pair<Iterator, bool>(Iterator(_root, _root),true);
			return { Iterator(_root,_root),true };//隐式类型转换
		}

		KeyOfT kot;
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data) < kot(data))//取key比较
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return  { 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)//注意如果grandparent是整个树的根,
		{//那么cur->_parent为空即parent为空再进循环parent->_col==RED就空指针解引用,所以要先判断parent是否为空
			Node* grandfather = parent->_parent;

			if(grandfather->_left ==parent)
			{
				//    g
				//  p   u
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_col == RED)//情况一
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上处理
					cur = grandfather;
					parent= cur->_parent;
				}
				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);
						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;///不管什么情况root都置为黑
		return{ Iterator(newnode, _root), true };
	}

	void RotateR(Node* parent)
	{
		// 记录 parent 的左孩子 subL 和 subL 的右孩子 subLR
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

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

		Node* Pparent = parent->_parent;

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

		if (Pparent == nullptr)//parent为根,修改根节点
		{
			_root = subL;
			subL->_parent = nullptr;//subL为根,根节点父指针置空
		}
		else//将Pparent与新节点subL链接
		{

			subL->_parent = Pparent;
			// 判断 parent 原来是祖父节点的左孩子还是右孩子
			if (Pparent->_left == parent)
			{
				Pparent->_left = subL;

			}
			else
			{
				Pparent->_right = subL;
			}
		}
	}

	void RotateL(Node* parent)
	{
		// 1. 记录parent的右孩子subR,以及subR的左孩子subRL
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		// 2. 将subRL变成parent的右孩子
		parent->_right = subRL;
		// 如果subRL不为空,更新它的父指针指向parent
		if (subRL)
			subRL->_parent = parent;

		// 3. 记录parent原来的父节点(祖父节点)
		Node* Pparent = parent->_parent;

		// 4. 将parent变成subR的左孩子
		subR->_left = parent;
		parent->_parent = subR;

		// 5. 将subR与祖父节点链接
		if (Pparent == nullptr)  // parent原来是根节点
		{
			_root = subR;           // 更新根节点为subR
			subR->_parent = nullptr; // 新根节点的父指针置空
		}
		else  // parent不是根节点
		{
			subR->_parent = Pparent;  // subR的父指针指向祖父节点
			// 判断parent原来是祖父节点的左孩子还是右孩子
			if (Pparent->_left == parent)
			{
				Pparent->_left = subR;   // 祖父节点的左孩子指向subR
			}
			else
			{
				Pparent->_right = subR;  // 祖父节点的右孩子指向subR
			}
		}
	}



	int Height()
	{
		return _Height(_root);
	}

	int Size()
	{
		return _size(_root);
	}

	Node* Find(const T& data)
	{
		KeyOfT kot;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_data)< kot(data))
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > kot(data))
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

	bool Check(Node* root, int blackNum, const int refNum)
	{
		KeyOfT kot;
		if (root == nullptr)
		{
			// 前序遍历⾛到空时,意味着⼀条路径⾛完了
			//cout << blackNum << endl;
			if (refNum != blackNum)
			{
				cout << "存在黑色结点的数量不相等的路径" << endl;
				return false;
			}
			return true;
		}
		// 检查孩⼦不太⽅便,因为孩⼦有两个,且不⼀定存在,反过来检查⽗亲就⽅便多了
		if (root->_col == RED && root->_parent->_col == RED)
		{

			cout << kot(root->_data) << "存在连续的红色结点" << endl;
			return false;
		}
		if (root->_col == BLACK)
		{
			blackNum++;
		}
		return Check(root->_left, blackNum, refNum)
			&& Check(root->_right, blackNum, refNum);
	}



	// 析构函数
	~RBTree()
	{
		clear();
	}

	// 清空树
	void clear()
	{
		Destroy(_root);
		_root = nullptr;
	}

	// 拷贝构造函数 - 如果需要深拷贝
	RBTree(const RBTree& other)
	{
		if (other._root)
		{
			_root = Copy(other._root, nullptr);
		}
	}

	// 赋值运算符 - 如果需要深拷贝
	RBTree& operator=(const RBTree& other)
	{
		if (this != &other)
		{
			clear();  // 先清理当前资源
			if (other._root)
			{
				_root = Copy(other._root, nullptr);
			}
		}
		return *this;
	}
	
private:
	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

	int _size(Node* root)
	{
		if (root == nullptr)
			return 0;
		return _size(root->_left) + 1 + _size(root->_right);
	}

	// 递归销毁辅助函数
	void Destroy(Node* root)
	{
		if (root == nullptr)
			return;

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

	// 深拷贝辅助函数(如果需要拷贝功能)
	Node* Copy(Node* root, Node* parent)
	{
		if (root == nullptr)
			return nullptr;

		Node* newNode = new Node(root->_data);
		newNode->_col = root->_col;
		newNode->_parent = parent;

		newNode->_left = Copy(root->_left, newNode);
		newNode->_right = Copy(root->_right, newNode);

		return newNode;
	}

	Node* _root = nullptr;
};

MyMap.h

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include "RBTree.h"


namespace name
{
	template<class K, class V>
	class Map
	{	
		struct MapOfT
		{
			const K& operator()(const pair<K,V>& kv)
			{
				return kv.first;
			}
		};

	public:
		typedef typename RBTree<K, pair<const K, V>, MapOfT>::Iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, MapOfT>::Const_Iterator 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>& data)
		{
			return _t.Insert(data);
		}

		V& operator[](const K& key)
		{
			// insert返回 pair<iterator, bool>
			// - iterator: 指向插入节点或已存在节点的迭代器
			// - bool: true表示插入成功,false表示key已存在
			pair<iterator, bool> ret = insert({ key, V() });

			// ret.first: 迭代器,指向节点中的pair<const K, V>
			// ret.first->second: 访问该pair的value部分
			// 无论插入成功还是失败,都返回key对应的value引用
			return ret.first->second;
		}
	private:
		RBTree<K, pair<const K,V>, MapOfT> _t;
	};
}

MySet.h

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include "RBTree.h"

namespace name
{
	template<class K>
	class Set
	{
		struct SetOfT//兼容map
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		//内部类或者typedef的类型就是内嵌类型,内嵌类型是可以通过::直接取到
		//通过::也可以静态成员,但是当该类是模板时,编译器无法区分Iterator是静态成员还是类型,
		// 编译器也无法在为实例化的模板里面去确认这个到底是类型还是变量,于是编译出错
		// RBTree<K, K, SetOfT>::Iterator 是一个"依赖类型"
		// 编译器在解析模板时不知道Iterator是一个类型还是静态成员
		typedef typename RBTree<K, const K, SetOfT>::Iterator iterator;  // 正确!
		//     告诉编译器这是一个类型
		typedef typename RBTree<K, const K, SetOfT>::Const_Iterator const_iterator;
		
		
		pair<iterator,bool> insert(const K& data)
		{
			return _t.Insert(data);
		}
		iterator begin()
		{
			return _t.Begin();
		}
		iterator end()
		{
			return _t.End();
		}

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

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

Test.cpp

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include"MyMap.h"

#include"MySet.h"


//// 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
//};
//// 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;
//};
//// stl_tree.h
//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;
//};
//template <class Value>
//struct __rb_tree_node : public __rb_tree_node_base
//{
//	typedef __rb_tree_node<Value>* link_type;
//	Value value_field;
//}; 




void test1()
{
	name::Set<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(0);
	s.insert(9);
	s.insert(6);
	s.insert(2);
	s.insert(5);
	name::Set<int>::iterator sit = s.begin();
	while (sit != s.end())
	{
		/**sit += 10;"sit": 不能给常量赋值*/
		cout << *sit << " ";
		++sit;
	}
	cout << endl;

	name::Set<int>::iterator sit2 = s.begin();
	cout << "test" << endl;
	for (int i = 0; i < 7; i++)
	{
		cout << *sit2 << endl;
		++sit2;
	}
	for (int i = 0; i < 8; i++)
	{
		cout << *sit2 << endl;
		--sit2;

	}
	name::Map<int, int> m;
	m.insert({ 1,4 });
	m.insert({ 5,4 });
	m.insert({ 6,4 });
	m.insert({ 9,4 });
	m.insert({ 2,4 });
	m.insert({ 8,4 });
	name::Map<int, int>::iterator mit = m.begin();
	while (mit != m.end())
	{
		//mit->first += 10; 表达式必须是可修改的左值
		mit->second += 10;
		cout << mit->first << ":" << mit->second << " ";
		cout << (*mit).first << ":" << (*mit).second << " ";
		++mit;
	}
	cout << endl;

	name::Map<string, string> dict;
	dict.insert({ "c","4" });
	dict.insert({ "a","4" });
	dict.insert({ "d","4" });
	dict.insert({ "b","4" });
	dict.insert({ "e","4" });

	name::Map<string, string>::iterator dictit = dict.begin();
	while (dictit != dict.end())
	{
		cout << dictit->first << ":" << dictit->second << " ";
		//cout << (*dictit).first << ":" << (*dictit).second << " ";
		++dictit;
	}
	cout << endl;

	for (auto& x : s)
	{
		cout << x << " ";
	}
	cout << endl;
	for (auto& e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
}

void reversePrint(const name::Set<int>& s)
{
	name::Set<int>::const_iterator it = s.end();
	while (it!=s.begin())
	{
		--it;
		cout << *it << " ";
	}
	cout << endl;
}


void test2()
{
	name::Set<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(0);
	s.insert(9);
	s.insert(6);
	s.insert(2);
	s.insert(5);
	cout << "正向遍历" << endl;
	for (const int& e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "反向遍历" << endl;
	reversePrint(s);
}


void test3()
{
	name::Map<string, string> dict;
	dict.insert({ "sort", "排序" });
	dict.insert({ "left", "左边" });
	dict.insert({ "right", "右边" });

	// 1. key已存在:查找并修改
	// operator[]调用insert,返回已有节点的value引用,然后修改
	dict["left"] = "左边,剩余";

	// 2. key不存在:插入+修改
	// insert先插入{"insert", ""},返回value引用,然后修改为"插⼊"
	dict["insert"] = "插入";

	// 3. key不存在:仅插入
	// insert插入{"string", ""},返回value引用,但没有赋值
	// 效果:字典中新增了"string"键,值为空字符串
	dict["string"];

	for (auto &e:dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
}

int main()
{
	test1();
	test2();
	test3();
	return 0;
}
相关推荐
老四啊laosi2 小时前
[C++进阶] 19. map && set的使用
c++·set·map·算法题
阿贵---2 小时前
模板编译期循环展开
开发语言·c++·算法
2601_954023662 小时前
Beyond the Hype: Deconstructing the 2025 High-Performance Stack for Agencies
java·开发语言·算法·seo·wordpress·gpl
沉鱼.442 小时前
滑动窗口问题
数据结构·算法
ysa0510302 小时前
二分+前缀(预处理神力2)
数据结构·c++·笔记·算法
2401_833197732 小时前
嵌入式C++电源管理
开发语言·c++·算法
灰色小旋风2 小时前
力扣22 括号生成(C++)
开发语言·数据结构·c++·算法·leetcode
寒月小酒2 小时前
3.23 OJ
数据结构·c++·算法
2501_924952692 小时前
模板编译期哈希计算
开发语言·c++·算法