C++ 模拟实现map&set

目录

一、改造红黑树

1、模板T改造节点

2、提取节点中的key 

3、迭代器类

operator++ 

operator--

4、改造insert

5、红黑树迭代器 

6、 普通迭代器构造const迭代器

二、set

三、map


在stl中map和set的结构中,他们都使用一个红黑树进行封装。

由上图可知,set传给红黑树节点的两个模板参数都是key,而map传给的红黑树的第一个模板参数是key、第二个参数是pair,因此我们首先对上一篇文章中的红黑树进行改造。

一、改造红黑树

#pragma once

enum Colour
{
	RED,
	BLACK,
};

template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data;
	Colour _col;

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

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)
	{}

	// 1、typedef __RBTreeIterator<T, T&, T*> itertaor;  拷贝构造
	// 2、 typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
	//  支持普通迭代器构造const迭代器的构造函数

	__RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)
		:_node(it._node)
	{}

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

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

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

	Self& operator++()
	{
		if (_node->_right)
		{
			// 1、右不为空,下一个就是右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}

			_node = subLeft;
		}
		else
		{
			// 2、右为空,沿着到根的路径,找孩子是父亲左的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

	Self& operator--()
	{
		if (_node->_left)
		{
			// 1、左不为空,找左子树最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}

			_node = subRight;
		}
		else
		{
			// 2、左为空,孩子是父亲的右的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}
};

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}
public:
	typedef __RBTreeIterator<T, T&, T*> itertaor;
	typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;

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

		return itertaor(cur);
	}

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

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

		return const_itertaor(cur);
	}

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

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

		return nullptr;
	}

	pair<itertaor, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;

			return make_pair(itertaor(_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(itertaor(cur), false);
			}
		}

		cur = new Node(data);
		Node* newnode = cur;
		if (kot(parent->_data) > kot(data))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				// 情况1:u存在且为红,变色处理,并继续往上处理
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					// 继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else // 情况2+3:u不存在/u存在且为黑,旋转+变色
				{
					//     g
					//   p   u
					// c 
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//     g
						//   p   u
						//     c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						//parent->_col = RED;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else // (grandfather->_right == parent)
			{
				//    g
				//  u   p
				//        c
				Node* uncle = grandfather->_left;
				// 情况1:u存在且为红,变色处理,并继续往上处理
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					// 继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else // 情况2+3:u不存在/u存在且为黑,旋转+变色
				{
					//    g
					//  u   p
					//        c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						//    g
						//  u   p
						//    c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;

		return make_pair(itertaor(newnode), true);;
	}

	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			cout << "根节点颜色是红色" << endl;
			return false;
		}

		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				++benchmark;
			cur = cur->_left;
		}

		// 连续红色节点
		return _Check(_root, 0, benchmark);
	}

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

private:
	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

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

	int _Height(Node* root)
	{
		if (root == NULL)
			return 0;

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		return leftH > rightH ? leftH + 1 : rightH + 1;
	}

	bool _Check(Node* root, int blackNum, int benchmark)
	{
		if (root == nullptr)
		{
			if (benchmark != blackNum)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				return false;
			}

			return true;
		}

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

		if (root->_col == RED 
			&& root->_parent 
			&& root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}

		return _Check(root->_left, blackNum, benchmark)
			&& _Check(root->_right, blackNum, benchmark);
	}

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

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

		Node* ppnode = parent->_parent;

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

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

			subR->_parent = ppnode;
		}
	}

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

private:
	Node* _root = nullptr;
};

1、模板T改造节点

我们需要将节点结构体RBTreeNode中的数据成员_data的类型改为模板参数T。这样,每个节点就可以存储不同类型的数据,以适应map的节点存储pair结构,set的节点存储key。

template<class T>
struct RBTreeNode
{
    RBTreeNode<T>* _left;
    RBTreeNode<T>* _right;
    RBTreeNode<T>* _parent;
    T _data;
    Colour _col;

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

2、提取节点中的key 

在上述代码中,我们可以看到`RBTree`类的定义如下:

template<class K, class T, class KeyOfT>
class RBTree
{
    // ...
};

其中,`K`是键的类型,`T`是值的类型,`KeyOfT`是一个辅助类也叫作仿函数,用于从值中提取键。在`set`中,键和值的类型相同,因此`KeyOfT`可以直接使用`K`。而在`map`中,键和值的类型不同,因此我们需要对`KeyOfT`进行修改。

对于`map`类,我们需要将`KeyOfT`修改为适应`pair<const K, V>`类型的辅助类。我们可以定义一个新的辅助类(仿函数)`MapKeyOfT`,其内部使用重载了函数调用运算符 operator(),这个辅助类的作用是从`pair<const K, V>`类型的值中提取出键`K`。同时,我们将`RBTree`的第三个模板参数修改为`MapKeyOfT`。

template<class K, class V>
class map
{
	struct MapKeyOfT
	{
		const K& operator()(const pair<const K, V>& kv)
		{
			return kv.first;
		}
	};
private:
	RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};

对于`set`类,我们需要将`KeyOfT`修改为配合map使用的辅助类。我们可以定义一个仿函数`SetKeyOfT`, 通过重载operator()直接返回key。同时,我们将第三个模板参数修改为’SetKeyOfT'。

template<class K>
class set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
private:
	RBTree<K, K, SetKeyOfT> _t;
};

3、迭代器类

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)
	{}

	// 1、typedef __RBTreeIterator<T, T&, T*> itertaor;  拷贝构造
	// 2、 typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
	//  支持普通迭代器构造const迭代器的构造函数

	__RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)
		:_node(it._node)
	{}

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

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

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

 这段代码定义了一个模板类__RBTreeIterator,它有三个模板参数:TRefPtr

  • T:表示节点中存储的数据类型。
  • Ref:表示解引用操作符*返回的引用类型。
  • Ptr:表示箭头操作符->返回的指针类型。

这个迭代器类用于遍历红黑树,并提供了对节点数据的访问功能。

在这个迭代器类中,有一个成员变量Node* _node,它指向红黑树中的一个节点。

  1. 构造函数__RBTreeIterator(Node* node)用于初始化迭代器对象,将_node指针指向传入的节点。
  2. 拷贝构造函数__RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)用于从普通迭代器构造const迭代器。它将传入迭代器的_node指针赋值给当前迭代器的_node成员变量。
  3. 重载解引用操作符*,使得可以通过迭代器访问节点的数据。它返回的是Ref类型的引用,可以直接修改节点的数据。
  4. 重载箭头操作符->,使得可以通过迭代器访问节点的数据。它返回的是Ptr类型的指针,可以通过指针访问节点的数据成员。
  5. 重载不等于操作符!=,用于比较两个迭代器是否不相等。它比较两个迭代器的_node指针是否相等。
  6. 重载前缀递增操作符++,使得可以将迭代器指向下一个节点。如果当前节点有右子节点,则下一个节点是右子树的最左节点;否则,沿着到根的路径,找到第一个孩子是父节点左孩子的祖先节点。
  7. 重载前缀递减操作符--,使得可以将迭代器指向上一个节点。如果当前节点有左子节点,则上一个节点是左子树的最右节点;否则,沿着到根的路径,找到第一个孩子是父节点右孩子的祖先节点。

operator++ 

    Self& operator++()
	{
		if (_node->_right)
		{
			// 1、右不为空,下一个就是右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}

			_node = subLeft;
		}
		else
		{
			// 2、右为空,沿着到根的路径,找孩子是父亲左的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

首先,函数检查当前节点的右子节点是否存在。如果存在,说明存在右子树,下一个节点就是右子树中的最左节点。因此,函数将迭代器指向右子树中的最左节点,并结束函数的执行。

如果当前节点的右子节点为空,说明不存在右子树。在这种情况下,函数需要沿着到根的路径向上查找,直到找到一个节点,该节点是其父节点的左子节点。这是因为在红黑树中,右子树为空的节点的下一个节点是其父节点。

函数使用两个指针变量 cur 和 parent 来进行查找。

  • 开始时,将 cur 初始化为当前节点,将 parent 初始化为 cur 的父节点。
  • 然后,函数进入一个循环,只要 parent 存在且 cur 是 parent 的右子节点,就继续向上查找。
  • 在循环中,将 cur 更新为 parent,将 parent 更新为 cur 的父节点。
  • 这样,函数就可以找到下一个节点,并将迭代器指向该节点。

最后,函数返回迭代器自身的引用,以支持链式操作。

operator--

	Self& operator--()
	{
		if (_node->_left)
		{
			// 1、左不为空,找左子树最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}

			_node = subRight;
		}
		else
		{
			// 2、左为空,孩子是父亲的右的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

 首先,函数检查当前节点的左子节点是否存在。如果存在,说明存在左子树,前一个节点就是左子树中的最右节点。因此,函数将迭代器指向左子树中的最右节点,并结束函数的执行。

如果当前节点的左子节点为空,说明不存在左子树。在这种情况下,函数需要沿着到根的路径向上查找,直到找到一个节点,该节点是其父节点的右子节点。这是因为在红黑树中,左子树为空的节点的前一个节点是其父节点。

函数使用两个指针变量 cur 和 parent 来进行查找。

  • 开始时,将 cur 初始化为当前节点,将 parent 初始化为 cur 的父节点。
  • 然后,函数进入一个循环,只要 parent 存在且 cur 是 parent 的左子节点,就继续向上查找。
  • 在循环中,将 cur 更新为 parent,将 parent 更新为 cur 的父节点。
  • 这样,函数就可以找到前一个节点,并将迭代器指向该节点。

最后,函数返回迭代器自身的引用,以支持链式操作。

4、改造insert

1. 修改函数的参数类型为 `const T& data`,以接受要插入的数据。

返回类型 pair<iterator, bool> 是为了提供更多的信息给调用者,以便在插入操作后进行进一步的处理。

pair<iterator, bool> Insert(const T& data)
  • iterator:表示插入节点的迭代器。通过返回迭代器,调用者可以方便地访问插入的节点,进行后续的操作,如修改节点的值、删除节点等。

  • bool:表示插入是否成功的标志。通过返回布尔值,调用者可以知道插入操作是否成功。如果插入成功,布尔值为 true;如果插入失败(节点已存在),布尔值为 false

 

2. 将 `pair<K, V>` 替换为 `T`,因为现在的节点类型是 `RBTreeNode<T>`。

cur = new Node(data);

3. 在函数内部,将 `_kv` 替换为 `_data`,以匹配节点的数据成员名称。

if (cur->_data < data){
    // ...
}
else if (cur->_data > data){
    // ...
}
else{//查找失败
    return make_pair(iterator(cur), false);
}

4.  新增的 KeyOfT kot; 是为了创建 KeyOfT 类型的对象 kot,用于从节点数据类型 T 中提取键值。

KeyOfT kot;
while (cur)
{
	if (kot(cur->_data) < kot(data))
	{//..}
	else if (kot(cur->_data) > kot(data))
	{//..}
	else
	{//..}
}

5. 在修改后的 Insert 函数中,新增的 Node* newnode = cur; 是为了在返回 pair<iterator, bool> 时,将插入的节点的迭代器保存下来。

Node* newnode = cur;
  • 在原始的代码中,返回的迭代器是通过 iterator(cur) 创建的,其中 cur 是指向新插入节点的指针。然而,在后续的操作中,cur 的值可能会发生变化,因为在红黑树的调整过程中,节点的位置可能会发生改变。
  • 为了确保返回的迭代器指向插入的节点,我们将 cur 的值保存在 newnode 中。这样,在返回 pair<iterator, bool> 时,我们使用 iterator(newnode) 创建迭代器,确保迭代器指向插入的节点。
  • 因此,Node* newnode = cur; 的目的是为了保存插入节点的指针,以便在返回迭代器时使用。这样可以确保返回的迭代器指向正确的节点,而不受后续操作的影响。

6. 在函数的返回语句中,使用 `make_pair` 创建一个 `pair` 对象,其中包含插入的迭代器和插入是否成功的标志。

return make_pair(iterator(newnode), true);

5、红黑树迭代器 

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __RBTreeIterator<T, T&, T*> itertaor;
	typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;

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

		return itertaor(cur);
	}

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

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

		return const_itertaor(cur);
	}

	const_itertaor end() const
	{
		return const_itertaor(nullptr);
	}
  • 首先,我们定义了两个迭代器类型 iterator 和 const_iterator,分别对应可修改和只读的迭代器。这些迭代器是通过 __RBTreeIterator 结构体模板实例化得到的。
  • 然后,我们定义了 begin() 和 end() 函数,分别用于返回红黑树的起始迭代器和结束迭代器。
  • 在 begin() 函数中,我们从根节点开始,沿着左子节点的路径向下遍历,直到找到最左边的节点。这个节点就是红黑树中最小的节点,也是起始节点。我们将其作为参数传递给 __RBTreeIterator 构造函数,创建一个迭代器对象,并将其返回。
  • 在 end() 函数中,我们直接返回一个迭代器对象,其指针成员 _node 设置为 nullptr,表示结束位置。
  • 对于 const 重载的版本,逻辑与非 const 版本相同,只是返回的是 const_iterator 类型的迭代器对象。

6、 普通迭代器构造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)
	{}

	// 1、typedef __RBTreeIterator<T, T&, T*> itertaor;  拷贝构造
	// 2、 typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
	//  支持普通迭代器构造const迭代器的构造函数

	__RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)
		:_node(it._node)
	{}
}
  • const __RBTreeIterator<T, T&, T*>& it 部分没有显式的强制类型转换。它是一个常量引用,用于接收普通迭代器对象的引用作为参数,如果需要将普通迭代器对象转换为const迭代器对象,编译器会自动进行隐式类型转换。
  • 因为参数加上了const修饰符,这意味着它是一个常量引用。当使用普通迭代器对象调用构造函数时,编译器会进行隐式类型转换,将普通迭代器对象转换为const迭代器对象。

二、set

#pragma once

#include "RBTree.h"

namespace MySet
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::const_itertaor iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_itertaor const_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;
	};
}
  • 在命名空间MySet中,定义了一个内部结构体SetKeyOfT,它是一个仿函数,用于从键中提取键值。在这个仿函数中,重载了函数调用操作符operator(),接受一个键key作为参数,并返回该键本身。
  • 接下来是set类的定义。它使用了模板参数K,表示集合中元素的类型。在set类中,使用了RBTree类来实现红黑树的功能。RBTree的模板参数为K、K和SetKeyOfT,表示键的类型、值的类型和键提取仿函数的类型。
  • set类中定义了两个迭代器类型:iterator和const_iterator,它们分别是RBTree<K, K, SetKeyOfT>::const_iterator的别名。这两个迭代器类型用于遍历集合中的元素。
  • set类还提供了begin和end方法,用于返回集合的起始迭代器和结束迭代器。begin方法返回的是红黑树的起始迭代器,而end方法返回的是红黑树的结束迭代器。
  • 此外,set类还提供了insert方法,用于向集合中插入元素。它接受一个键key作为参数,并返回一个pair对象,其中包含一个迭代器和一个布尔值。迭代器指向插入的元素,布尔值表示插入是否成功。
  • 最后,set类中有一个私有成员变量_t,它是一个RBTree<K, K, SetKeyOfT>类型的对象,用于存储集合的元素。

三、map

#pragma once

#include "RBTree.h"

namespace MyMap
{
	template<class K, class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::itertaor iterator;

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

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

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

		pair<iterator, bool> insert(const pair<const K, V>& kv)
		{
			return _t.Insert(kv);
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
  • 命名空间MyMap中,定义了一个内部结构体MapKeyOfT,它是一个仿函数,用于从键值对中提取键。在这个仿函数中,重载了函数调用操作符operator(),接受一个键值对kv作为参数,并返回该键值对中的键first
  • 接下来是map类的定义。它使用了两个模板参数KV,分别表示键和值的类型。在map类中,使用了RBTree类来实现红黑树的功能。RBTree的模板参数为Kpair<const K, V>MapKeyOfT,表示键的类型、键值对的类型和键提取仿函数的类型。
  • map类中定义了一个迭代器类型iterator,它是RBTree<K, pair<const K, V>, MapKeyOfT>::iterator的别名。这个迭代器类型用于遍历映射中的键值对。
  • map类提供了beginend方法,用于返回映射的起始迭代器和结束迭代器。begin方法返回的是红黑树的起始迭代器,而end方法返回的是红黑树的结束迭代器。
  • 此外,map类还重载了下标操作符[],使得可以通过键访问对应的值。它接受一个键key作为参数,并返回对应的值的引用。如果键不存在于映射中,则会自动插入一个新的键值对,并返回对应值的引用。
  • map类还提供了insert方法,用于向映射中插入键值对。它接受一个键值对kv作为参数,并返回一个pair对象,其中包含一个迭代器和一个布尔值。迭代器指向插入的键值对,布尔值表示插入是否成功。
  • 最后,map类中有一个私有成员变量_t,它是一个RBTree<K, pair<const K, V>, MapKeyOfT>类型的对象,用于存储映射的键值对。

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-01-27 02:14:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-27 02:14:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-27 02:14:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-27 02:14:01       20 阅读

热门阅读

  1. vue开发的PC端项目使用postcss-to-viewport适配移动端

    2024-01-27 02:14:01       40 阅读
  2. WordPress wp-file-manager 文件上传漏洞 CVE-2020-25213

    2024-01-27 02:14:01       30 阅读
  3. element中form校验中清除校验不通过的提示语

    2024-01-27 02:14:01       36 阅读
  4. 【Git】Conventional Commit提交规范

    2024-01-27 02:14:01       29 阅读
  5. [GN] Vue3.2 快速上手 ----常用API及其新组件

    2024-01-27 02:14:01       31 阅读
  6. CentOS7开机自动执行脚本

    2024-01-27 02:14:01       38 阅读
  7. 算法37:最大矩形(力扣84、85题)---单调栈

    2024-01-27 02:14:01       37 阅读
  8. KMean 聚类

    2024-01-27 02:14:01       36 阅读
  9. LED闪烁

    2024-01-27 02:14:01       30 阅读