【C++】:STL详解 —— 红黑树封装map和set

news2025/3/10 12:36:44

目录

红黑树的源代码

正向迭代器的代码

反向迭代器的代码

set的模拟实现

map的模拟实现


红黑树的源代码

#pragma once
#include <iostream>

using namespace std;
// set ->key
// map ->key/value


// set ->key
// map ->key/value

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

// 红黑树正向迭代器模板
// 模板参数:
//   T    - 结点数据类型
//   Ref  - 数据的引用类型
//   Ptr  - 数据的指针类型
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
	typedef RBTreeNode<T> Node;					// 红黑树结点类型
	typedef __TreeIterator<T, Ref, Ptr> Self;	// 迭代器自身类型

	Node* _node;								// 当前迭代器持有的结点指针

	// 构造函数
	// 参数:
	//   node - 需要包装的结点指针
	__TreeIterator(Node* node)
		: _node(node)  // 初始化持有的结点指针
	{}

	// 解引用操作符(获取数据引用)
	Ref operator*()
	{
		return _node->_data;  // 返回结点存储数据的引用
	}

	// 箭头操作符(获取数据指针)
	Ptr operator->()
	{
		return &_node->_data;  // 返回指向结点数据的指针
	}

	// 不等比较操作符
	// 参数:
	//   s - 要比较的迭代器
	// 返回值: 两个迭代器是否指向不同结点
	bool operator!=(const Self& s) const
	{
		return _node != s._node;  // 直接比较结点指针
	}

	// 相等比较操作符
	// 参数:
	//   s - 要比较的迭代器
	// 返回值: 两个迭代器是否指向相同结点
	bool operator==(const Self& s) const
	{
		return _node == s._node;  // 直接比较结点指针
	}

	// 前置自增操作符(中序遍历顺序的下一个结点)
	Self operator++()
	{
		if (_node->_right)  // 当前结点存在右子树
		{
			// 寻找右子树的最左结点(右子树中的最小结点)
			Node* left = _node->_right;
			while (left->_left)
			{
				left = left->_left;
			}
			_node = left;
		}
		else  // 当前结点没有右子树
		{
			// 向上寻找第一个不是右孩子的祖先结点
			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)  // 当前结点存在左子树
		{
			// 寻找左子树的最右结点(左子树中的最大结点)
			Node* right = _node->_left;
			while (right->_right)
			{
				right = right->_right;
			}
			_node = right;
		}
		else  // 当前结点没有左子树
		{
			// 向上寻找第一个不是左孩子的祖先结点
			Node* cur = _node;
			Node* parent = cur->_parent;

			// 沿着父指针向上查找,直到当前结点是父结点的右孩子
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;  // 最终定位到的父结点即为前驱
		}
		return *this;
	}
};

//反向迭代器---迭代器适配器
template<class Iterator>
struct ReverseIterator
{
	typedef ReverseIterator<Iterator> Self; //反向迭代器的类型
	typedef typename Iterator::reference Ref; //结点指针的引用
	typedef typename Iterator::pointer Ptr; //结点指针

	Iterator _it; //反向迭代器所封装的正向迭代器

	//构造函数
	ReverseIterator(Iterator it)
		:_it(it) //根据所给正向迭代器构造一个反向迭代器
	{}

	Ref operator*()
	{
		return *_it; //通过调用正向迭代器的operator*返回结点数据的引用
	}
	Ptr operator->()
	{
		return _it.operator->(); //通过调用正向迭代器的operator->返回结点数据的指针
	}

	//前置++
	Self& operator++()
	{
		--_it; //调用正向迭代器的前置--
		return *this;
	}
	//前置--
	Self& operator--()
	{
		++_it; //调用正向迭代器的前置++
		return *this;
	}

	bool operator!=(const Self& s) const
	{
		return _it != s._it; //调用正向迭代器的operator!=
	}
	bool operator==(const Self& s) const
	{
		return _it == s._it; //调用正向迭代器的operator==
	}
};

// set->RBTree<K, K, SetKeyOfT> _t;
// map->RBTree<K, pair<const K, T>, MapKeyOfT> _t;
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __TreeIterator<T, T&, T*> iterator;			//正向迭代器
	typedef __TreeIterator<T, const T&, const T*> const_iterator;

	typedef ReverseIterator<iterator> reverse_iterator; //反向迭代器
	typedef ReverseIterator<const_iterator> const_reverse_iterator; 

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

		return iterator(cur);
	}

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

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

		return const_iterator(cur);
	}

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

	reverse_iterator rbegin()
	{
		//寻找最右结点
		Node* right = _root;
		while (right && right->_right)
		{
			right = right->_right;
		}
		//返回最右结点的反向迭代器
		return reverse_iterator(iterator(right));
	}

	reverse_iterator rend()
	{
		//返回由nullptr构造得到的反向迭代器(不严谨)
		return reverse_iterator(iterator(nullptr));
	}

	const_reverse_iterator rbegin() const
	{
		//寻找最右结点
		Node* right = _root;
		while (right && right->_right)
		{
			right = right->_right;
		}
		//返回最右结点的反向迭代器
		return const_reverse_iterator(const_iterator(right));
	}
	const_reverse_iterator rend() const
	{
		//返回由nullptr构造得到的反向迭代器(不严谨)
		return const_reverse_iterator(const_iterator(nullptr));
	}
	//构造函数
	RBTree()
		:_root(nullptr)
	{}

	//拷贝构造
	RBTree(const RBTree<K, T, KeyOfT>& t)
	{
		_root = _Copy(t._root, nullptr);
	}

	//赋值运算符重载(现代写法)
	RBTree<K, T, KeyOfT>& operator=(RBTree<K, T, KeyOfT> t)
	{
		swap(_root, t._root);
		return *this; //支持连续赋值
	}

	//析构函数
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}

	size_t Size()
	{
		return _Size(_root);
	}

	bool Empty() const 
	{
		return _root == nullptr;
	}
	void Clear() 
	{
		_Destroy(_root);
		_root = nullptr;
	}

	void Swap(Node& other) 
	{
		std::swap(_root, other._root);
	}

	//pair<iterator, bool> Insert(const T& data)
	pair<Node*, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return make_pair(_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(cur, false);
			}
		}

		// 新增节点给红色
		cur = new Node(data);
		Node* newnode = cur;
		cur->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
				//     g
				//   p   u
				// c
				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
						// c
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						// 双旋
						//     g
						//   p
						//     c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else  // parent == grandfather->_right
			{
				//     g
				//   u   p 
				//          c
				//
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)
				{
					// 变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					// 继续往上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					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(newnode, true);
	}
	//删除函数
	bool Erase(const K& key)
	{
		KeyOfT kot;
		//用于遍历二叉树
		Node* parent = nullptr;
		Node* cur = _root;
		//用于标记实际的待删除结点及其父结点
		Node* delParentPos = nullptr;
		Node* delPos = nullptr;
		while (cur)
		{
			if (key < kot(cur->_data)) //所给key值小于当前结点的key值
			{
				//往该结点的左子树走
				parent = cur;
				cur = cur->_left;
			}
			else if (key > kot(cur->_data)) //所给key值大于当前结点的key值
			{
				//往该结点的右子树走
				parent = cur;
				cur = cur->_right;
			}
			else //找到了待删除结点
			{
				if (cur->_left == nullptr) //待删除结点的左子树为空
				{
					if (cur == _root) //待删除结点是根结点
					{
						_root = _root->_right; //让根结点的右子树作为新的根结点
						if (_root)
						{
							_root->_parent = nullptr;
							_root->_col = BLACK; //根结点为黑色
						}
						delete cur; //删除原根结点
						return true;
					}
					else
					{
						delParentPos = parent; //标记实际删除结点的父结点
						delPos = cur; //标记实际删除的结点
					}
					break; //进行红黑树的调整以及结点的实际删除
				}
				else if (cur->_right == nullptr) //待删除结点的右子树为空
				{
					if (cur == _root) //待删除结点是根结点
					{
						_root = _root->_left; //让根结点的左子树作为新的根结点
						if (_root)
						{
							_root->_parent = nullptr;
							_root->_col = BLACK; //根结点为黑色
						}
						delete cur; //删除原根结点
						return true;
					}
					else
					{
						delParentPos = parent; //标记实际删除结点的父结点
						delPos = cur; //标记实际删除的结点
					}
					break; //进行红黑树的调整以及结点的实际删除
				}
				else //待删除结点的左右子树均不为空
				{
					//替换法删除
					//寻找待删除结点右子树当中key值最小的结点作为实际删除结点
					Node* minParent = cur;
					Node* minRight = cur->_right;
					while (minRight->_left)
					{
						minParent = minRight;
						minRight = minRight->_left;
					}
					cur->_data = minRight->_data; //将待删除结点的_data改为minRight的_data
					delParentPos = minParent; //标记实际删除结点的父结点
					delPos = minRight; //标记实际删除的结点
					break; //进行红黑树的调整以及结点的实际删除
				}
			}
		}
		if (delPos == nullptr) //delPos没有被修改过,说明没有找到待删除结点
		{
			return false;
		}

		//记录待删除结点及其父结点(用于后续实际删除)
		Node* del = delPos;
		Node* delP = delParentPos;

		//调整红黑树
		if (delPos->_col == BLACK) //删除的是黑色结点
		{
			if (delPos->_left) //待删除结点有一个红色的左孩子(不可能是黑色)
			{
				delPos->_left->_col = BLACK; //将这个红色的左孩子变黑即可
			}
			else if (delPos->_right) //待删除结点有一个红色的右孩子(不可能是黑色)
			{
				delPos->_right->_col = BLACK; //将这个红色的右孩子变黑即可
			}
			else //待删除结点的左右均为空
			{
				while (delPos != _root) //可能一直调整到根结点
				{
					if (delPos == delParentPos->_left) //待删除结点是其父结点的左孩子
					{
						Node* brother = delParentPos->_right; //兄弟结点是其父结点的右孩子
						//情况一:brother为红色
						if (brother->_col == RED)
						{
							delParentPos->_col = RED;
							brother->_col = BLACK;
							RotateL(delParentPos);
							//需要继续处理
							brother = delParentPos->_right; //更新brother(否则在本循环中执行其他情况的代码会出错)
						}
						//情况二:brother为黑色,且其左右孩子都是黑色结点或为空
						if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
							&& ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
						{
							brother->_col = RED;
							if (delParentPos->_col == RED)
							{
								delParentPos->_col = BLACK;
								break;
							}
							//需要继续处理
							delPos = delParentPos;
							delParentPos = delPos->_parent;
						}
						else
						{
							//情况三:brother为黑色,且其左孩子是红色结点,右孩子是黑色结点或为空
							if ((brother->_right == nullptr) || (brother->_right->_col == BLACK))
							{
								brother->_left->_col = BLACK;
								brother->_col = RED;
								RotateR(brother);
								//需要继续处理
								brother = delParentPos->_right; //更新brother(否则执行下面情况四的代码会出错)
							}
							//情况四:brother为黑色,且其右孩子是红色结点
							brother->_col = delParentPos->_col;
							delParentPos->_col = BLACK;
							brother->_right->_col = BLACK;
							RotateL(delParentPos);
							break; //情况四执行完毕后调整一定结束
						}
					}
					else //delPos == delParentPos->_right //待删除结点是其父结点的左孩子
					{
						Node* brother = delParentPos->_left; //兄弟结点是其父结点的左孩子
						//情况一:brother为红色
						if (brother->_col == RED) //brother为红色
						{
							delParentPos->_col = RED;
							brother->_col = BLACK;
							RotateR(delParentPos);
							//需要继续处理
							brother = delParentPos->_left; //更新brother(否则在本循环中执行其他情况的代码会出错)
						}
						//情况二:brother为黑色,且其左右孩子都是黑色结点或为空
						if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
							&& ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
						{
							brother->_col = RED;
							if (delParentPos->_col == RED)
							{
								delParentPos->_col = BLACK;
								break;
							}
							//需要继续处理
							delPos = delParentPos;
							delParentPos = delPos->_parent;
						}
						else
						{
							//情况三:brother为黑色,且其右孩子是红色结点,左孩子是黑色结点或为空
							if ((brother->_left == nullptr) || (brother->_left->_col == BLACK))
							{
								brother->_right->_col = BLACK;
								brother->_col = RED;
								RotateL(brother);
								//需要继续处理
								brother = delParentPos->_left; //更新brother(否则执行下面情况四的代码会出错)
							}
							//情况四:brother为黑色,且其左孩子是红色结点
							brother->_col = delParentPos->_col;
							delParentPos->_col = BLACK;
							brother->_left->_col = BLACK;
							RotateR(delParentPos);
							break; //情况四执行完毕后调整一定结束
						}
					}
				}
			}
		}
		//进行实际删除
		if (del->_left == nullptr) //实际删除结点的左子树为空
		{
			if (del == delP->_left) //实际删除结点是其父结点的左孩子
			{
				delP->_left = del->_right;
				if (del->_right)
					del->_right->_parent = delP;
			}
			else //实际删除结点是其父结点的右孩子
			{
				delP->_right = del->_right;
				if (del->_right)
					del->_right->_parent = delP;
			}
		}
		else //实际删除结点的右子树为空
		{
			if (del == delP->_left) //实际删除结点是其父结点的左孩子
			{
				delP->_left = del->_left;
				if (del->_left)
					del->_left->_parent = delP;
			}
			else //实际删除结点是其父结点的右孩子
			{
				delP->_right = del->_left;
				if (del->_left)
					del->_left->_parent = delP;
			}
		}
		delete del; //实际删除结点
		return true;
	}

	//查找函数
	const_iterator Find(const K& key) const
	{
		KeyOfT kot;
		Node* cur = _root;
		while (cur)
		{
			if (key < kot(cur->_data))	//key值小于该结点的值
			{
				cur = cur->_left;		//在该结点的左子树当中查找
			}
			else if (key > kot(cur->_data)) //key值大于该结点的值
			{
				cur = cur->_right;			//在该结点的右子树当中查找
			}
			else //找到了目标结点
			{
				return const_iterator(cur); //返回该结点
			}
		}
		return end(); //查找失败
	}

	
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	// 根节点->当前节点这条路径的黑色节点的数量
	bool Check(Node* root, int blacknum, const int refVal)
	{
		if (root == nullptr)
		{
			//cout << balcknum << endl;
			if (blacknum != refVal)
			{
				cout << "存在黑色节点数量不相等的路径" << endl;
				return false;
			}

			return true;
		}

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

			return false;
		}

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

		return Check(root->_left, blacknum, refVal)
			&& Check(root->_right, blacknum, refVal);
	}

	bool IsBalance()
	{
		if (_root == nullptr)
			return true;

		if (_root->_col == RED)
			return false;

		//参考值
		int refVal = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				++refVal;
			}

			cur = cur->_left;
		}

		int blacknum = 0;
		return Check(_root, blacknum, refVal);
	}

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

private:
	size_t _Size(Node* root)
	{
		if (root == NULL)
			return 0;

		return _Size(root->_left)
			+ _Size(root->_right) + 1;
	}
	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;
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}
	//拷贝树
	Node* _Copy(Node* root, Node* parent)
	{
		if (root == nullptr)
		{
			return nullptr;
		}
		Node* copyNode = new Node(root->_data);
		copyNode->_parent = parent;
		copyNode->_left = _Copy(root->_left, copyNode);
		copyNode->_right = _Copy(root->_right, copyNode);
		return copyNode;
	}

	//析构函数子函数
	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}

	//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* parentParent = parent->_parent;

		//建立subRL与parent之间的联系
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		//建立parent与subR之间的联系
		subR->_left = parent;
		parent->_parent = subR;

		//建立subR与parentParent之间的联系
		if (parentParent == nullptr)
		{
			_root = subR;
			_root->_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;
		Node* parentParent = parent->_parent;

		//建立subLR与parent之间的联系
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		//建立parent与subL之间的联系
		subL->_right = parent;
		parent->_parent = subL;

		//建立subL与parentParent之间的联系
		if (parentParent == nullptr)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (parent == parentParent->_left)
			{
				parentParent->_left = subL;
			}
			else
			{
				parentParent->_right = subL;
			}
			subL->_parent = parentParent;
		}
	}

	//左右双旋
	void RotateLR(Node* parent)
	{
		RotateL(parent->_left);
		RotateR(parent);
	}

	//右左双旋
	void RotateRL(Node* parent)
	{
		RotateR(parent->_right);
		RotateL(parent);
	}

	Node* _root; //红黑树的根结点	
};

正向迭代器的代码

// 红黑树正向迭代器模板
// 模板参数:
//   T    - 结点数据类型
//   Ref  - 数据的引用类型
//   Ptr  - 数据的指针类型
template<class T, class Ref, class Ptr>
struct __TreeIterator 
{
    typedef Ref reference;    // 数据引用类型定义
    typedef Ptr pointer;      // 数据指针类型定义

    typedef RBTreeNode<T> Node;          // 红黑树结点类型
    typedef __TreeIterator<T, Ref, Ptr> Self;  // 迭代器自身类型

    Node* _node;  // 当前迭代器持有的结点指针

    // 构造函数
    // 参数:
    //   node - 需要包装的结点指针
    __TreeIterator(Node* node)
        : _node(node)  // 初始化持有的结点指针
    {}

    // 解引用操作符(获取数据引用)
    Ref operator*() 
    {
        return _node->_data;  // 返回结点存储数据的引用
    }

    // 箭头操作符(获取数据指针)
    Ptr operator->() 
    {
        return &_node->_data;  // 返回指向结点数据的指针
    }

    // 不等比较操作符
    // 参数:
    //   s - 要比较的迭代器
    // 返回值: 两个迭代器是否指向不同结点
    bool operator!=(const Self& s) const 
    {
        return _node != s._node;  // 直接比较结点指针
    }

    // 相等比较操作符
    // 参数:
    //   s - 要比较的迭代器
    // 返回值: 两个迭代器是否指向相同结点
    bool operator==(const Self& s) const 
    {
        return _node == s._node;  // 直接比较结点指针
    }

    // 前置自增操作符(中序遍历顺序的下一个结点)
    Self operator++() 
    {
        if (_node->_right)  // 当前结点存在右子树
        {
            // 寻找右子树的最左结点(右子树中的最小结点)
            Node* left = _node->_right;
            while (left->_left) 
            {
                left = left->_left;
            }
            _node = left;
        }
        else  // 当前结点没有右子树
        {
            // 向上寻找第一个不是右孩子的祖先结点
            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)  // 当前结点存在左子树
        {
            // 寻找左子树的最右结点(左子树中的最大结点)
            Node* right = _node->_left;
            while (right->_right) 
            {
                right = right->_right;
            }
            _node = right;
        }
        else  // 当前结点没有左子树
        {
            // 向上寻找第一个不是左孩子的祖先结点
            Node* cur = _node;
            Node* parent = cur->_parent;
            
            // 沿着父指针向上查找,直到当前结点是父结点的右孩子
            while (parent && cur == parent->_left) 
            {
                cur = parent;
                parent = parent->_parent;
            }
            _node = parent;  // 最终定位到的父结点即为前驱
        }
        return *this;
    }
};

反向迭代器的代码

//反向迭代器---迭代器适配器
template<class Iterator>
struct ReverseIterator
{
	typedef ReverseIterator<Iterator> Self; //反向迭代器的类型
	typedef typename Iterator::reference Ref; //结点指针的引用
	typedef typename Iterator::pointer Ptr; //结点指针

	Iterator _it; //反向迭代器所封装的正向迭代器

	//构造函数
	ReverseIterator(Iterator it)
		:_it(it) //根据所给正向迭代器构造一个反向迭代器
	{}

	Ref operator*()
	{
		return *_it; //通过调用正向迭代器的operator*返回结点数据的引用
	}
	Ptr operator->()
	{
		return _it.operator->(); //通过调用正向迭代器的operator->返回结点数据的指针
	}

	//前置++
	Self& operator++()
	{
		--_it; //调用正向迭代器的前置--
		return *this;
	}
	//前置--
	Self& operator--()
	{
		++_it; //调用正向迭代器的前置++
		return *this;
	}

	bool operator!=(const Self& s) const
	{
		return _it != s._it; //调用正向迭代器的operator!=
	}
	bool operator==(const Self& s) const
	{
		return _it == s._it; //调用正向迭代器的operator==
	}
};

set的模拟实现

成员函数功能
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
empty判断容器是否为空
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数
#pragma once
#include"RBTree.h"

namespace wh
{
	template<class K>
	class set
	{
	public:
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
		
		typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;			//正向迭代器
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

		typedef typename RBTree<K, K, SetKeyOfT>::reverse_iterator reverse_iterator; //反向迭代器
		typedef typename RBTree<K, K, SetKeyOfT>::const_reverse_iterator const_reverse_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();
		}
		// 获取反向起始迭代器(指向最后一个元素)
		reverse_iterator rbegin()
		{
			return _t.rbegin();
		}

		// 获取反向结束迭代器(指向起始哨兵节点)
		reverse_iterator rend()
		{
			return _t.rend();
		}

		// 获取反向起始迭代器(指向最后一个元素)
		const_reverse_iterator rbegin() const
		{
			return _t.rbegin();
		}

		// 获取反向结束迭代器(指向起始哨兵节点)
		const_reverse_iterator rend() const
		{
			return _t.rend();
		}

		pair<iterator, bool> insert(const K& key)
		{
			return _t.Insert(key);
		}
		// 删除函数
		void erase(const K& key)
		{
			_t.Erase(key);
		}
		// 查找函数
		const_iterator find(const K& key) const
		{
			return _t.Find(key);
		}
		// 获取容器中元素的个数
		size_t size()
		{
			return _t.Size();
		}
		// 获取容器中指定元素值的元素个数
		size_t count(const K& key) const
		{
			return _t.Find(key) != _t.end() ? 1 : 0;
		}
		// 判断容器是否为空
		bool empty() const
		{
			return _t.Empty();
		}
		// 清空容器
		void clear()
		{
			_t.Clear();
		}
		void swap(set& other)
		{
			_t.Swap(other._t);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}

map的模拟实现

接口分类接口名称作用
插入操作insert插入键值对,返回插入结果(迭代器 + 是否成功)。
emplace原地构造键值对,避免临时对象拷贝。
operator[]通过键访问值(若键不存在,插入默认值并返回引用)。
删除操作erase删除指定键或迭代器范围内的键值对。
clear清空所有键值对。
查找与访问find查找键,返回迭代器(未找到返回 end())。
count返回键的数量(0 或 1)。
contains (C++20)检查键是否存在,返回布尔值。
at安全访问值(键不存在时抛出异常)。
容量查询empty检查容器是否为空。
size返回键值对数量。
迭代器begin / end获取正向迭代器(按键升序)。
rbegin / rend获取反向迭代器(按键降序)。
#pragma once
#include"RBTree.h"

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

		// 对类模板取内嵌类型,加typename告诉编译器这里是类型
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::reverse_iterator reverse_iterator;
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_reverse_iterator const_reverse_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();
        }

        // 获取反向起始迭代器(指向最后一个元素)
        reverse_iterator rbegin()
        {
            return _t.rbegin();
        }

        // 获取反向结束迭代器(指向起始哨兵节点)
        reverse_iterator rend()
        {
            return _t.rend();
        }

        // 获取反向起始迭代器(指向最后一个元素)
        const_reverse_iterator rbegin() const
        {
            return _t.rbegin();
        }

        // 获取反向结束迭代器(指向起始哨兵节点)
        const_reverse_iterator rend() const
        {
            return _t.rend();
        }

        // 插入键值对
        // 参数: kv - 要插入的键值对
        // 返回值: 包含迭代器和插入结果的 pair
        pair<iterator, bool> insert(const pair<const K, V>& kv)
        {
            return _t.Insert(kv);
        }

        // 下标访问运算符重载
        // 参数: key - 要访问的键
        // 返回值: 对应值的引用(若键不存在则自动插入默认值)
        V& operator[](const K& key)
        {
            // 尝试插入键值对(若存在则获取已存在的元素)
            pair<iterator, bool> ret = insert(make_pair(key, V()));
            iterator it = ret.first;     // 获取迭代器
            return it->second;            // 返回值的引用
        }

        // 删除指定键的元素
        // 参数: key - 要删除的键
        void erase(const K& key)
        {
            _t.Erase(key);
        }

        // 查找指定键的元素
        // 参数: key - 要查找的键
        // 返回值: 指向元素的迭代器(若未找到则返回 end())
        iterator find(const K& key)
        {
            return _t.Find(key);
        }
		// 获取容器中元素的个数
		size_t size()
		{
			return _t.Size();
		}
		// 获取容器中指定元素值的元素个数
		size_t count(const K& key) const
		{
			return _t.Find(key) != _t.end() ? 1 : 0;
		}
		// 判断容器是否为空
		bool empty() const
		{
			return _t.Empty();
		}
		// 清空容器
		void clear()
		{
			_t.Clear();
		}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2312695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【c++】平移字符串

说明 实现字符串的左移与右移 示例代码 #include <iostream> #include <string> using namespace std;int main() {string str1 "12345";//左移2位string str2 str1.substr(2) str1.substr(0, 2);cout << str2 << endl;//右移2位&…

为什么DDPG需要目标网络而A2C不需要?

在强化学习中&#xff0c;DDPG需要目标网络而A2C不需要的主要原因在于算法架构、更新方式和目标稳定性需求的差异&#xff1a; Q值估计的稳定性需求不同 DDPG的Critic网络需要估计状态-动作值函数 Q ( s , a ) Q(s,a) Q(s,a)&#xff0c;其目标值的计算涉及下一个状态的最大Q值…

蓝桥杯 C++ b组 统计子矩阵深度解析

题目大意&#xff1a;给定一个 NM 的矩阵 A&#xff0c;请你统计有多少个子矩阵 (最小11&#xff0c;最大NM) 满足子矩阵中所有数的和不超过给定的整数 K&#xff1f; 前言&#xff1a;这题很容易想到二维前缀和优化&#xff0c;然后枚举子矩阵&#xff0c;但这样时间复杂度为…

YOLOv12本地部署教程——42%速度提升,让高效目标检测触手可及

YOLOv12 是“你只看一次”&#xff08;You Only Look Once, YOLO&#xff09;系列的最新版本&#xff0c;于 2025 年 2 月发布。它引入了注意力机制&#xff0c;提升了检测精度&#xff0c;同时保持了高效的实时性能。在保持速度的同时&#xff0c;显著提升了检测精度。例如&am…

认识Event Loop【1】

前言 这应该是一个系列文章&#xff0c;因为我觉得Event Loop&#xff08;事件循环&#xff09;是一件很抽象也很重要的一个机制。eventloop这个知识点处于非常杂糅的位置&#xff0c;和很多其他知识&#xff0c;如运行时、浏览器、渲染流程、数据结构、线程等等&#xff0c;也…

《Linux栈破坏了,如何还原》

【栈破坏导读】栈破坏有了解过吗&#xff1f;何为栈破坏&#xff0c;栈破坏了&#xff0c;程序会立刻引发崩溃&#xff0c;我们通过gdb去调试coredump&#xff0c;栈被破坏的栈帧是没法被恢复的&#xff0c;这也给我们调试程序带来很大的困难&#xff0c;那如何还原栈破坏的第一…

环形链表问题的探究与代码实现

在数据结构与算法的学习中&#xff0c;环形链表是一个经典的问题。它不仅考察对链表这种数据结构的理解&#xff0c;还涉及到指针操作和逻辑推理。本文将结合代码和图文&#xff0c;深入分析如何判断链表中是否有环以及如何找到环的入口点。 目录 一、判断链表中是否有环 …

【CSS3】筑基篇

目录 复合选择器后代选择器子选择器并集选择器交集选择器伪类选择器 CSS 三大特性继承性层叠性优先级 背景属性背景色背景图背景图平铺方式背景图位置背景图缩放背景图固定背景复合属性 显示模式显示模式块级元素行内元素行内块元素 转换显示模式 结构伪类选择器结构伪类选择器…

React:类组件(上)

kerwin老师我来了 类组件的创建 class组件&#xff0c;js里的类命名首字符大写&#xff0c;类里面包括构造函数&#xff0c;方法 组件类要继承React.Component才有效 必须包含render方法 import React from react class App extends React.Component{render() {return <…

Spring Cloud之注册中心之Nacos的使用

目录 Naacos 服务注册/服务发现 引⼊Spring Cloud Alibaba依赖 引入Nacos依赖 引入Load Balance依赖 配置Nacos地址 服务端调用 启动服务 Naacos Nacos是Spring Cloud Alibaba的组件, Spring Cloud Alibaba遵循Spring Cloud中定义的服务注册, 服务发现规范. 因此使⽤Na…

字符串相乘——力扣

给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 "3" …

基于OpenCV的车牌识别系统(源码+论文+部署教程)

运行环境 基于OpenCV的车牌识别系统运行环境如下&#xff1a; • Python: ≥ 3.5 • OpenCV: ≥ 4.0 • IDE工具&#xff1a;Visual Studio Code&#xff08;可自行选择&#xff09; • 技术栈&#xff1a;Python OpenCV Tkinte 主要功能 基于OpenCV的车牌识别系统主要…

MySQL:CRUD(增删查改)

目录 一、准备工作 二、Create 新增 1、语法 2、单行数据全列插入 3、单行数据指定列插入 4、多行数据指定列插入 5、多行数据全列插入 三、Retrieve 检索 1、语法 2、全列查询 3、指定列查询 4、查询字段为表达式 &#xff08;1&#xff09;常量表达式 &…

【git】【网络】【项目配置运行】HTTP 协议的微型简易 Web 服务器---tinyEasyMuduoWebServer

【git】【网络】【项目配置运行】HTTP 协议的微型简易 Web 服务器—tinyEasyMuduoWebServer csdn项目&#xff1a; 原文链接&#xff1a;https://blog.csdn.net/weixin_45178775/article/details/122257814 github链接&#xff1a;https://github.com/wyewyewye/tinyEasyMuduo…

Python入门———条件、循环

目录 语句 顺序语句 条件语句 缩进和代码块 判断年份是否是闰年 空语句 pass 循环 while 循环 求5的阶乘&#xff1a; 求1&#xff01;2&#xff01;3&#xff01;4&#xff01;5&#xff01; for循环 打印1-10 打印2&#xff0c;4&#xff0c;6&#xff0c;8&#x…

InDraw6.2.3 | 甾体、核苷、黄酮类化合物实现简称命名

导语 当化学家对着屏幕输入"2-amino-1,9-dihydro-6H-purin-6-one"时&#xff0c;隔壁生物学家可能正在搜索"鸟嘌呤"&#xff1b;这种命名差异如同"火星文"与"地球语"的碰撞。现在&#xff0c;鹰谷InDraw 6.2.3版带着53种多环化合物的…

Linux中的TCP编程接口基本使用

TCP编程接口基本使用 本篇介绍 在UDP编程接口基本使用已经介绍过UDP编程相关的接口&#xff0c;本篇开始介绍TCP编程相关的接口。有了UDP编程的基础&#xff0c;理解TCP相关的接口会更加容易&#xff0c;下面将按照两个方向使用TCP编程接口&#xff1a; 基本使用TCP编程接口…

系统部署【信创名录】及其查询地址

一、信创类型 &#xff08;一&#xff09;服务器&#xff1a; 1.华为云 2.腾讯云 3.阿里云 &#xff08;二&#xff09;中央处理器&#xff08;CPU&#xff09;&#xff1a; 1.海思&#xff0c;鲲鹏920服务器 &#xff08;三&#xff09;中间件 1.人大金仓 &#xff0…

JavaWeb后端基础(7)AOP

AOP是Spring框架的核心之一&#xff0c;那什么是AOP&#xff1f;AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;面向切面编程就是面向特定方法编程。AOP是一种思想&#xff0c;而在Spring框…

Unity DOTS从入门到精通之EntityCommandBufferSystem

文章目录 前言安装 DOTS 包ECBECB可以执行的指令示例&#xff1a; 前言 DOTS&#xff08;面向数据的技术堆栈&#xff09;是一套由 Unity 提供支持的技术&#xff0c;用于提供高性能游戏开发解决方案&#xff0c;特别适合需要处理大量数据的游戏&#xff0c;例如大型开放世界游…