目录

红黑树的源代码

正向迭代器的代码

反向迭代器的代码

set的模拟实现

map的模拟实现


红黑树的源代码

#pragma once
#include <iostream>using namespace std;
// set ->key
// map ->key/value// set ->key
// map ->key/valueenum 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// cNode* 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// cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// 双旋//     g//   p//     cRotateL(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的_datadelParentPos = 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 - 要插入的键值对// 返回值: 包含迭代器和插入结果的 pairpair<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.pswp.cn/bicheng/72900.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/72900.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/72900.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB控制函数测试要点剖析

一、功能准确性检验 基础功能核验 针对常用控制函数&#xff0c;像用于传递函数建模的 tf 、构建状态空间模型的 ss &#xff0c;以及开展阶跃响应分析的 step 等&#xff0c;必须确认其能精准执行基础操作。以 tf 函数为例&#xff0c;在输入分子与分母系数后&#xff0c;理…

MoonSharp 文档一

目录 1.Getting Started 步骤1&#xff1a;在 IDE 中引入 MoonSharp 步骤2&#xff1a;引入命名空间 步骤3&#xff1a;调用脚本 步骤4&#xff1a;运行代码 2.Keeping a Script around 步骤1&#xff1a;复现前教程所有操作 步骤2&#xff1a;改为创建Script对象 步骤…

ROS云课三分钟-差动移动机器人导航报告如何撰写-及格边缘疯狂试探

提示词&#xff1a;基于如上所有案例并结合roslaunch teb_local_planner_tutorials robot_diff_drive_in_stage.launch和上面所有对话内容&#xff0c;设计一个差速移动机器人仿真实验&#xff0c;并完成报告的全文撰写。 差速移动机器人导航仿真实验报告 一、实验目的 验证 T…

ACE协议学习1

在多核系统或复杂SoC&#xff08;System on Chip&#xff09;中&#xff0c;不同处理器核心或IP&#xff08;Intellectual Property&#xff09;模块之间需要保持数据的一致性。常用的是ACE协议or CHI。 先对ACE协议进行学习 ACE协议&#xff08;Advanced Microcontroller Bu…

ajax之生成一个ajax的demo示例

目录 一. node.js和express ​二. 使用express创建后端服务 三. 创建前端 一. node.js和express ajax是前端在不刷新的情况下访问后端的技术&#xff0c;所以首先需要配置一个后端服务&#xff0c;可以使用node.js和express。 首先生成一个空项目&#xff0c;新建main目录…

Java 字节码操纵框架 -ASM

Java 字节码操纵框架 -ASM 1.ASM 概述: ASM 是用于 Java 字节码操纵的框架,可动态生成新类或增强现有类的功能。它既能直接产生二进制 class 文件,也能在类被加载到虚拟机之前动态改变类行为,通过读取类文件信息来分析、修改类行为,甚至生成新类。许多流行框架如 cglib、…

kafka + flink +mysql 案例

假设你有两个Kafka主题&#xff1a;user_activities_topic 和 product_views_topic&#xff0c;并且你希望将user_activities_topic中的数据写入到user_activities表&#xff0c;而将product_views_topic中的数据写入到product_views表。 maven <dependencies><!-- …

远程登录客户端软件 CTerm 发布了 v4.0.0

有时候我们需要远程登录到 Linux/Unix 服务器&#xff0c;这方面使用最广泛的客户端软件是 PuTTY&#xff0c;不过它是全英文的&#xff0c;而且是单窗口的&#xff0c;有时候显得不那么方便。 CTerm (Clever Terminal) 是一个 Windows 平台下支持 Telnet 和 SSH 协议进行远程…

从李佳琦团队看新型用工:灵活就业如何重构组织架构?

2022年“双11”期间&#xff0c;李佳琦直播间累计销售额突破115亿元&#xff08;来源&#xff1a;新腕数据《2022双11直播电商战报》&#xff09;&#xff0c;其背后团队规模约400人&#xff0c;但全职员工仅占35%&#xff0c;其余65%为外包选品团队、兼职客服、第三方MCN机构人…

微软程序的打包格式MSIX

MSIX 微软推出的MSIX格式是其为统一Windows应用程序打包和部署而设计的新一代安装包格式&#xff0c;具有以下核心特点和进展&#xff1a; 1. 推出背景与时间线 MSIX最初于2018年在微软Build大会上宣布&#xff0c;并在同年7月发布预览版打包工具&#xff0c;10月正式版上线…

AFL++安装

学习fuzzing也几天了&#xff0c;今天记录AFL的安装及使用 一、实验环境 虚拟机&#xff1a;ubuntu20.04 当然也可以uname -a去看自己的版本号 二、AFL安装 1.先更新一下工具 sudo apt update2.安装AFL必要的一些依赖&#xff0c;例如编译工具&#xff08;如 build-essen…

【STM32】ADC功能-单通道多通道(学习笔记)

本章结合上一节内容复习更好理解【江协科技STM32】ADC数模转换器-学习笔记-CSDN博客 一、ADC单通道 接线图 ADC初始化 ①RCC开启时钟&#xff0c;包括ADC和GPIO的时钟&#xff0c;另外ADCCLK的分频器也要配置 ②配置GPIO,&#xff0c;把需要用的GPIO配置成模拟输入模式&am…

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

当前主流的大模型训练与推理框架的全面汇总

以下是当前主流的大模型训练与推理框架的全面汇总 以下是更新后包含 SGLang 的大模型训练与推理框架列表&#xff0c;并对分类和示例进行了优化&#xff1a; 一、通用深度学习推理框架 TensorRT-LLM 特点&#xff1a;NVIDIA推出的针对Transformer类模型的优化框架&#xff0c;支…

Linux学习(八)(服务管理(检查服务状态,开始/停止服务,检查服务日志,创建新服务))

服务管理 Linux 中的服务管理是指控制 Linux 在启动和关闭计算机的过程中启动和停止的服务&#xff08;或“守护程序”&#xff09;的系统。这些服务执行各种功能&#xff0c;并提供未附加到用户界面的进程。 Linux 系统&#xff0c;尤其是系统管理员&#xff0c;通常需要管理…

ElasticSearch 分词器介绍及测试:Standard(标准分词器)、English(英文分词器)、Chinese(中文分词器)、IK(IK 分词器)

ElasticSearch 分词器介绍及测试&#xff1a;Standard&#xff08;标准分词器&#xff09;、English&#xff08;英文分词器&#xff09;、Chinese&#xff08;中文分词器&#xff09;、IK&#xff08;IK 分词器&#xff09; ElasticSearch 分词器介绍及测试1. Standard Analyz…

【计算机网络】确认家庭网络是千兆/百兆带宽并排查问题

要确认你的带宽是千兆&#xff08;1000Mbps&#xff09;还是百兆&#xff08;100Mbps&#xff09;&#xff0c;可以通过以下方法逐步排查&#xff1a; 一、检查物理设备 1. 查看路由器和光猫的网口 千兆网口&#xff1a;路由器或光猫的网口旁通常会标注 “10/100/1000M” 或 …

[数据分享第七弹]全球洪水相关数据集

洪水是一种常见的自然灾害&#xff0c;在全球范围内造成了极为严重的威胁。近年来&#xff0c;针对洪水事件的检测分析&#xff0c;以及对于洪水灾害和灾后恢复能力的研究日渐增多&#xff0c;也产生了众多洪水数据集。今天&#xff0c;我们一起来收集整理一下相关数据集。&…

深入探讨AI-Ops架构 第一讲 - 运维的进化历程以及未来发展趋势

首先&#xff0c;让我们一起回顾运维的进化之路&#xff0c;然后再深入探讨AI-Ops架构的细节。 运维的进化历程 1. AI 大范围普及前的运维状态 (传统运维) 在AI技术尚未广泛渗透到运维领域之前&#xff0c;我们称之为传统运维&#xff0c;其主要特点是&#xff1a; 人工驱动…

Hive-数据倾斜优化

数据倾斜的原因 1&#xff09;key分布不均匀&#xff0c;本质上就是业务数据有可能会存在倾斜 2&#xff09;某些SQL语句本身就有数据倾斜 关键词 情形 后果 Join A、其中一个表较小&#xff0c;但是key集中; B、两张表都是大表&#xff0c;key不均 分发到…