✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨
✨ 个人主页:余辉zmh–CSDN博客
✨ 文章所属专栏:c++篇–CSDN博客
文章目录
- 前言
- 一.`set`和`map`的初步封装
- 1.树的节点封装修改
- 2.`Find()`查找函数
- 3.红黑树的封装修改
- 4.set和map的初步封装框架
- 二.红黑树的迭代器封装
- 1.基本框架
- 2.常用成员函数
- 3.前置`++`函数
- 4.前置`--`函数
- 5.红黑树封装中的迭代器函数
- 6.红黑树封装中的插入函数修改
- 三.set封装完整实现
- 1.set的迭代器函数
- 2.set的插入函数
- 3.测试
- 四.map封装完整实现
- 1.map的迭代器函数
- 2.map的插入函数
- 3.map的`operator[]`函数
- 4.测试
- 五.完整代码文件
- 1.`RBTree.h`文件
- 2.`Set.h`文件
- 3.`Map.h`文件
前言
在之前的文章中,我们知道,
set
和map
是两种常用的关联容器。他们内部通常使用红黑树来实现高效的查找,插入和删除操作,尽管它们提供了不同的接口函数,但它们依然可以通过共享相同的底层数据结构(也就是同一个红黑树)来实现。下面将详细讲解如何通过改造我们之前的红黑树来实现我们自己的set
和map
容器。(红黑树的实现在我上一篇文章中有详细讲解,不清楚的可以看我之前的文章)
一.set
和map
的初步封装
1.树的节点封装修改
首先我们来看一下我们之前的红黑树如何实现节点类的封装:
//节点类封装
template<class K,class V>
class RBTreeNode{
public:
//构造函数
RBTreeNode(const pair<K,V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{}
//成员变量
RBTree<K,V>* _left;
RBTree<K,V>* _right;
RBTree<K,V>* _parent;
pair<K,V> _kv;
Colour _col;
};
我们学完set和map应该已经知道,set存储的是一个key值,而map存储的是一个键值对key-value,在上面这段代码中,如果通过这两个模板参数可以实现map,但set却没办法使用,因此,这里节点类的两个模板参数需要使用一个泛型参数来修改,这样就可以实现set和map能够共享一颗树。
修改如下:
//RBTree.h文件
template<class T>
class RBTreeNode {
public:
//构造函数
RBTreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_col(RED)
{}
//成员变量
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
};
通过上面的修改为一个模板参数就可以实现共享效果:
set存储的是一个键值key,这里的模板参数T就是键值key的类型
map存储的是一个键值对key-value,这里的模板参数T就是容器pair<key,value> 类型
2.Find()
查找函数
在上面对节点封装进行修改后,这里又会产生新的问题,如果我们要通过键值Key来查找对应的节点(也就是Find()函数的参数是键值key,对于set来说直接通过键值key就能找到,但是map中的节点存储的是一个键值对key-value,也就是一个,pair(key,value)对象,直接通过参数key并不能查找,具体可以看下面函数
Node* Find(const K& key){
Node* cur=_root;
while(cur){
//对于set来说,_data就是key
//对于map来说,_data是一个piar(key,value)对象
if(cur->_data<key){
cur=cur->_right;
}
else if(cur->_data>key){
cur=cur->_left;
}
else{
return cur;
}
}
return nullptr;
}
因此为了解决这个问题,这里需要借助一个仿函数来实现两个不同容器的查找
-
set的仿函数:
struct SetKeyOfT{ const K& operator()(const K& key){ return key; } };
-
map的仿函数:
struct MapKeyOfT{ const K& operator()(const pair<K,V>& kv){ return kv.first; } };
-
Find()函数:
Node* Find(const K& key){ Node* cur=_root; //对于set来说,这里的KeyOfT就是SetKeyOfT //对于map来说,这里的KeyOfT就是MapKeyOfT KeyOfT kot; while(cur){ if(kot(cur->_data)){ cur=cur->_right; } else if(kot(cur->_data)>key){ cur=cur->_left; } else{ return cur; } } return nullptr; }
3.红黑树的封装修改
上面了解完如何实现两个不同容器之间的查找之后,这里就需要开始对原本的红黑树进行封装修改,从Find()函数中我们可以看到,需要一个新的模板参数KeyOfT,用来实现不同容器仿函数的查找功能。
修改如下:
//RBTree.h文件
//增加一个新的模板参数KeyOfT
template<class K,class V,class KeyOfT>
class RBTree{
typedef RBTreeNode<T> Node;
public:
//构造函数
RBTree()
:_root(nullptr)
{}
//Node* Find(const K& key);
//...其他成员函数
private:
Node* _root;
}
4.set和map的初步封装框架
有了前面三个的基础这里就可以开始对set和map进行初步的封装,set和map的底层都是借用同一个红黑树。
-
set的初步封装框架:
//Set.h文件 namesapce MySet{ template<class K> class Set{ //将仿函数设置为内部类 struct SetKeyOfT{ const K& operator()(const K& key){ return key; } }; public: //...其他成员函数 private: //第一个模板参数K是set存储的数据类型 RBTree<K,K,SetKeyOfT> _t; }; };
-
map的初步封装框架:
//Map.h文件 namesapce MyMap{ template<class K,class V> class Map{ //将仿函数设置为内部类 struct MapKeyOfT{ const K& operator()(const pair<K,V>& kv){ return kv.first; } }; public: //...其他成员函数 private: //第一个模板参数K是set存储的数据类型 RBTree<K,pair<const K,V>,MapKeyOfT> _t; }; };
二.红黑树的迭代器封装
这里红黑树的迭代器封装其实和容器list比较类似,不能像string和vector一样使用原生指针作为迭代器,只能通过封装结点指针来实现迭代器。
1.基本框架
//迭代器封装
template<class T,class Ptr,class Ref>
class TreeIterator{
//重命名定义
typedef RBTreeNode<T> Node;
typedef TreeIterator<T,Ptr,Ref> self;
public:
//节点指针
Node* _node;
//构造函数
TreeIterator(Node* node)
:_node(node)
{}
//...成员函数
}
2.常用成员函数
-
operator*
函数://T& operator*() //const T& operator*() //用模板参数Ref来实现两个不同返回类型的替换 Ref opeartor*(){ return _node->_data; }
-
operator->
函数://T* operator->() //const T* operator->() //用模板参数Ptr来实现两个不同返回类型的替换 Ptr operator->(){ return &_node->_data; }
-
operator!=
函数:bool operator!=(const self& s)const { return _node!=s._node; }
-
operator==
函数:bool operator==(const self& s)const { return _node==s._node; }
3.前置++
函数
self operator++(){
//如果该节点右子节点不为空,则到右子树中找最左节点
if(_node->_right){
Node* subleft=_node->_right;
while(subleft->_left){
subleft=subleft->_left;
}
_node=subleft;
}
//如果该节点右子节点为空,则找到该节点父节点的左子节点的祖先节点
else{
Node* cur=_node;
Node* parent=cur->_parent;
while(parent){
//如果cur节点是父节点的右子节点,继续往上
if(cur==parent->_right){
cur=parent;
parent=parent->_parent;
}
//如果cur节点是父节点的左子节点,停止
else{
break;
}
}
_node=parent;
}
return *this;
}
4.前置--
函数
self& operator--(){
if(_node->_left){
Node* subright=_node->_left;
while(subright->_right){
subright=subright->_right;
}
_node=subright;
}
else{
Node* cur=_node;
Node* parent=cur->_parent;
while(parent){
if(cur==parent->_left){
cur=parent;
parent=parent->_parent;
}
else{
break;
}
_node=parent;
}
return *this;
}
}
5.红黑树封装中的迭代器函数
对于红黑树来说,有普通对象迭代器和const对象迭代器。
template<class ,class T,class KeyOfT>
class RBTree{
//....
public:
//普通对象迭代器
typedef TreeIterator<T,T*,T&> iterator;
//const对象迭代器
typedef TreeIterator<T,const T*,const T&> const_iterator;
iterator begin(){
Node* cur=_root;
while(cur&&cur->_left){
cur=cur->_left;
}
return cur;
}
iterator end(){
return nullptr;
}
const_iterator begin()const {
Node* cur=_root;
while(cur&&cur->_left){
cur=cur->_left;
}
return cur;
}
const_iterator end()const {
return nullptr;
}
}
6.红黑树封装中的插入函数修改
有了前面红黑树封装的迭代器,这里插入函数就可以进行修改,从原本的bool类型,变为pair<iterator,bool>类型,其中,iterator表示插入位置的迭代器,如果差人成功,返回插入位置的迭代器和true;如果该值已经存在,返回该值位置的迭代器和false。
//这里第三个模板参数KeyOfT就可以用到
pair<iteraotr,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);
cur=_col=RED;
if(kot(parent->_data)<kot(data)){
parent->_right=cur;
}
else{
parent->_left=cur;
}
cur->_parent=parent;
//更新平衡因子,旋转,变色
//...
return make_pair(newnode,true);
}
三.set封装完整实现
1.set的迭代器函数
在前面通过对红黑树的迭代器进行封装之后,这里就可以直接实现set的迭代器函数
- 代码实现:
namespace MySet{
template<class K>
class set{
//内部类,用来获取set存储对象中的key值
struct SetKeyOfT{
const K& operator()(const K& key){
return key;
}
};
public:
//这里的类模板还没有实例化对象,所以要加上关键字typename
typedef typename RBTree<K,K,SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K,K,SetKeyOfT>::const_iterator const_iterator;
//set的begin()函数
const_iterator begin()const {
return _t.begin();
}
//set的end()函数
const_iterator end()const {
return _t.end();
}
private:
//第一个模板参数k是set存储的数据类型
RBTree<K,K,SetKeyOfT> _t;
};
};
-
实现原理:
-
首先就是要将红黑树原本的迭代器类型进行命名重定义,这里有一个注意点,因为
RBTree<K,K,SetKeyOfT>
是一个类模板,现在还没有进行实例化,所以直接加上作用域限定符::
后面加上迭代器类型会报错,因为编译器并不知道当前模板参数的具体类型,因此要加上关键字typename
。 -
其次set还有一个性质就是对于key值,不能进行修改,所以使用迭代器时,如果对于当前迭代器解引用获取key值,要求只能访问,不能修改。因此我们这里可以将set的普通类型迭代器
iterator
和const类型迭代器const_iterator
全都使用红黑树的const类型迭代器typename RBTree<K,K,SetKeyOfT>::const_iterator
。
-
2.set的插入函数
set的插入函数返回的是一个pair<iterator,bool>类型
pair<iterator,bool> insert(const K& key){
return _t.insert(key);
}
注意:set的返回类型pair<iterator,bool>表面上看起来是普通类型的迭代器,但其实,我们是将红黑树的const_iterator
迭代器重命名定义成了iterator
,因此pair<iterator,bool>
中的其实是const_iterator
,但是红黑树的插入函数返回的又是一个iterator
,所以这里直接写成上面的代码显然是错误的。
正确的写法是要进行一次类型转换:
pair<iterator,bool> insert(const K& key){
pair<typename RBTree<K,K,SetKeyOfT>::iterator ret=_t.insert(key);
return pair<iterator,bool>(ret.first,ret.second);
}
为了实现从iterator
类型转换为const_iterator
,我们要在红黑树的迭代器封装中添加一个构造函数
TreeIterator(Node* node)
:_node(node)
{}
3.测试
测试代码:
#include"Set.h"
int main(){
MySet::set<int> s;
s.insert(2);
s.insert(10);
s.insert(4);
s.insert(7);
MySet::set<int>::iterator sit=s.begin();
while(sit!=s.end()){
//(*sit)++;
//这里修改key值就会报错
cout<<*sit<<" ";
++sit;
}
cout<<endl;
return 0;
}
测试结果:
四.map封装完整实现
1.map的迭代器函数
这里map的迭代器函数和set的有些不同,因为set要求存储的key值不能被修改,而map只限定了键值对中的key值不能修改,而value值可以修改,所以这里使用红黑树类模板做参数时有些不同,通过pair<const K,V>
实现key值不能修改,而value值可以修改。
namespace MyMap{
template<class K,class V>
class Map{
struct MapKeyOfT{
const K& operator()(const pair<const K,V>& kv){
return kv.first;
}
};
public:
//map的普通迭代器iterator
typedef typename RBTree<K,pair<const K,V>,MapKeyOfT>::iterator iterator;
//map的const类型迭代器const_iterator
typedef typename RBTree<K,pair<const K,V>,MapKeyOfT>::const_iterator const_iterator;
iterator begin(){
return _t.begin();
}
iterator end(){
return _t.end();
}
const_iterator begin()const {
return _t.begin();
}
const_iterator end()const{
return _t.end();
}
//其他成员函数
//...
private:
RBTree<K,pair<const K,V>,MapKeyOfT> _t;
};
};
2.map的插入函数
相较于set的插入函数,map的插入函数就比较简单,直接调用函数即可
pair<iterator,bool> insert(const pair<const K,V>& kv){
return _t.insert(kv);
}
3.map的operator[]
函数
map相比于set还有一个其他的使用方法,就是[]
,[]
可以通过key值,返回value值。如果参数key值不存在map中,会将参数key值插入到map中,然后返回value的对应类型的初始化值,当然还可以通过[]
修改对应key值的value值。
V& operator[](const K& key){
//V()是模板参数V的默认构造
pair<iterator,bool> rit=insert(make_pair(key,v()));
return rit.first->second;
}
4.测试
测试代码:
#include"Map.h"
void test1(){
MyMap::Map<int,int> m;
m.insert(make_pair(3,3));
m.insert(make_pair(2,2));
m.insert(make_pair(1,1));
MyMap::Map<int,int>::iterator it=m.begin();
while(it!=m.end()){
//(it->first)++;
//这里对key值修改就会报错
cout<<it->first<<" "<<it->second<<endl;
++it;
}
cout<<endl;
m[3]=1;
m[4];
m[5]=100;
for(auto e : m){
cout<<e.first<<" "<<e.second<<endl;
}
}
int main(){
test1();
return 0;
}
测试结果:
五.完整代码文件
1.RBTree.h
文件
#include<iostream>
#include<utility>
#include<vector>
#include<time.h>
using namespace std;
enum Colour {
RED,
BLACK
};
template<class T>
class RBTreeNode {
public:
//构造函数
RBTreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_col(RED)
{}
//成员变量
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
};
//迭代器类封装
template<class T,class Ptr,class Ref>
class TreeIterator{
//重命名定义
typedef RBTreeNode<T> Node;
typedef TreeIterator<T,Ptr,Ref> self;
typedef TreeIterator<T,T*,T&> Iterator;
public:
Node* _node;
TreeIterator(Node* node)
:_node(node)
{}
TreeIterator(const Iterator& it)
:_node(it._node)
{}
Ref operator*(){
return _node->_data;
}
Ptr operator->(){
return &_node->_data;
}
bool operator!=(const self& s)const {
return _node !=s._node;
}
bool operator==(const self& s)const {
return _node==s._node;
}
self& operator++(){
//如果该节点右子节点不为空,则到右子树中找最左节点
if(_node->_right){
Node* subleft=_node->_right;
while(subleft->_left){
subleft=subleft->_left;
}
_node=subleft;
}
//如果该节点右子节点为空,则找到该节点父节点的左子节点的祖先节点
else{
Node* cur=_node;
Node* parent=cur->_parent;
while(parent){
//如果cur节点是父节点的右子节点,继续往上
if(cur==parent->_right){
cur=parent;
parent=parent->_parent;
}
//如果cur节点是父节点的左子节点,停止
else{
break;
}
}
_node=parent;
}
return *this;
}
self& operator--(){
//如果当前节点左子节点不为空,则到该节点的左子树中的最右节点
if(_node->_left){
Node* subright=_node->_left;
while(subright->_right){
subright=subright->_right;
}
_node=subright;
}
//如果该节点左子节点为空,就到该节点的祖先节点的右子节点
else{
Node* cur=_node;
Node* parent=cur->_parent;
while(parent){
if(cur==parent->_left){
cur=parent;
parent=parent->_parent;
}
else{
break;
}
}
_node=parent;
}
return *this;
}
};
template<class K , class T, class KeyOfT>
class RBTree {
typedef RBTreeNode<T> Node;
public:
//普通对象迭代器
typedef TreeIterator<T ,T* ,T&> iterator;
//const对象迭代器
typedef TreeIterator<T ,const T* ,const T&> const_iterator;
//构造函数
RBTree()
:_root(nullptr)
{}
iterator begin(){
Node* cur=_root;
while(cur&&cur->_left){
cur=cur->_left;
}
return cur;
}
iterator end(){
return nullptr;
}
const_iterator begin()const {
Node* cur=_root;
while(cur&&cur->_left){
cur=cur->_left;
}
return cur;
}
const_iterator end()const {
return nullptr;
}
Node* Find(const K& key){
Node* cur=_root;
KeyOfT kot;
while(cur){
//这里参数key已经是K类型的,所以不用调用仿函数kot()
if(kot(cur->_data)<key){
cur=cur->_right;
}
else if(kot(cur->_data)>key){
cur=cur->_left;
}
else{
return cur;
}
}
return nullptr;
}
pair<iterator,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) {
//这里参数data是T类型的,是容器里存储的对象,不是K类型,所以要调用仿函数kot()获取key值
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);
cur->_col=RED;
if(kot(parent->_data)<kot(data)){
parent->_right=cur;
}
else{
parent->_left=cur;
}
cur->_parent=parent;
Node* newnode=cur;
while(parent&&parent->_col==RED){
Node* grandfather=parent->_parent;
//如果parent节点在左子节点
if(parent==grandfather->_left){
Node* uncle=grandfather->_right;
//如果uncle节点存在且节点为红色
if(uncle&&uncle->_col==RED){
//变色
parent->_col=uncle->_col=BLACK;
grandfather->_col=RED;
//继续往上
cur=grandfather;
parent=cur->_parent;
}
//如果uncle节点不存在 或者 节点为黑色
else{
//如果cur节点在左子节点
if(cur==parent->_left){
//右单旋
RotateR(grandfather);
//旋转后变色
grandfather->_col=RED;
parent->_col=BLACK;
}
//如果cur节点在右子节点
else{
//左双旋
//先左单旋,再右单旋
RotateL(parent);
RotateR(grandfather);
//旋转后变色
cur->_col=BLACK;
grandfather->_col=RED;
}
break;
}
}
//如果parent节点在右子节点
else{
Node* uncle=grandfather->_left;
//如果uncle节点存在且节点为红色
if(uncle&&uncle->_col==RED){
//变色
parent->_col=uncle->_col=BLACK;
grandfather->_col=RED;
//继续往上
cur=grandfather;
parent=cur->_parent;
}
//如果uncle节点不存在 后者 节点为黑色
else{
//如果cur节点在右子节点
if(cur==parent->_right){
//左单旋
RotateL(grandfather);
//变色
parent->_col=BLACK;
grandfather->_col=RED;
}
//如果cur节点在左子节点
else{
//右双旋
//先右单旋,再左单旋
RotateR(parent);
RotateL(grandfather);
//旋转后变色
cur->_col=BLACK;
grandfather->_col=RED;
}
break;
}
}
}
_root->_col=BLACK;
return make_pair(newnode,true);
}
int Height(){
return _Height(_root);
}
bool IsBlance(){
return _IsBlance(_root);
}
private:
int _Height(Node* root){
if(root==nullptr){
return 0;
}
int leftheight=_Height(root->_left);
int rightheight=_Height(root->_right);
return leftheight>rightheight ? leftheight+1 : rightheight+1;
}
bool CheckColour(Node* root,int blacknum,int benchmark){
//如果节点是空,判断黑色节点个数是否等于基准值
if(root==nullptr){
if(blacknum!=benchmark){
return false;
}
return true;
}
//如果节点是黑色,黑色个数加加
if(root->_col==BLACK){
blacknum++;
}
//如果节点是红色,判断父节点是否也是红色,不能出现连续的红色节点
if(root->_col==RED&&root->_parent&&root->_parent->_col==RED){
cout<<root->_kv.first<<"RED False"<<endl;
return false;
}
return CheckColour(root->_left,blacknum,benchmark)
&&CheckColour(root->_right,blacknum,benchmark);
}
bool _IsBlance(Node* root){
if(root==nullptr){
return true;
}
//如果根节点不是黑色,返回错误
if(root->_col!=BLACK){
return false;
}
//设置一个基准值
int benchmark=0;
Node* cur=root;
while(cur){
if(cur->_col==BLACK){
benchmark++;
}
cur=cur->_left;
}
return CheckColour(root,0,benchmark);
}
//左单旋
void RotateL(Node* parent){
Node* cur=parent->_right;
Node* curleft=cur->_left;
Node* ppnode=parent->_parent;
parent->_right=curleft;
if(curleft){
curleft->_parent=parent;
}
cur->_left=parent;
parent->_parent=cur;
if(ppnode){
if(ppnode->_left==parent){
ppnode->_left=cur;
cur->_parent=ppnode;
}
else{
ppnode->_right=cur;
cur->_parent=ppnode;
}
}
else{
cur->_parent=nullptr;
_root=cur;
}
}
//右单旋
void RotateR(Node* parent){
Node* cur=parent->_left;
Node* curright=cur->_right;
Node* ppnode=parent->_parent;
parent->_left=curright;
if(curright){
curright->_parent=parent;
}
cur->_right=parent;
parent->_parent=cur;
if(ppnode){
if(ppnode->_left==parent){
ppnode->_left=cur;
cur->_parent=ppnode;
}
else{
ppnode->_right=cur;
cur->_parent=ppnode;
}
}
else{
cur->_parent=nullptr;
_root=cur;
}
}
private:
Node* _root;
};
2.Set.h
文件
#include"RBTree.h"
namespace MySet{
template<class K>
class set{
//内部类,用来获取set存储对象中的key值
struct SetKeyOfT{
const K& operator()(const K& key){
return key;
}
};
public:
//这里的类模板还没有实例化对象,所以要加上关键字typename
typedef typename RBTree<K,K,SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K,K,SetKeyOfT>::const_iterator const_iterator;
const_iterator begin()const {
return _t.begin();
}
const_iterator end()const {
return _t.end();
}
//这里返回的是const_iterator类型的迭代器
pair<iterator,bool> insert(const K& key){
//插入返回的是iterator类型的迭代器
pair<typename RBTree<K,K,SetKeyOfT>::iterator,bool> ret=_t.insert(key);
return pair<iterator,bool>(ret.first,ret.second);
}
private:
//第一个模板参数k是set存储的数据类型
RBTree<K,K,SetKeyOfT> _t;
};
};
3.Map.h
文件
#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>::iterator iterator;
typedef typename RBTree<K,pair<const K,V>,MapKeyOfT>::const_iterator const_iterator;
iterator begin(){
return _t.begin();
}
iterator end(){
return _t.end();
}
const_iterator begin()const {
return _t.begin();
}
const_iterator end()const{
return _t.end();
}
//operator[],通过key值,返回value值,具备插入和修改
V& operator[](const K& key){
pair<iterator,bool> rit=insert(make_pair(key,V()));
return rit.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;
};
};
以上就是关于set和map的封装讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!