【C++】:STL詳解 —— 紅黑樹封裝map和set

目錄

紅黑樹的源代碼

正向迭代器的代碼

反向迭代器的代碼

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不均 分發到…