当前位置: 首页 > news >正文

set和map的封装(C++)

目录

1、前言

2、通过源码进行分析

3、泛型红黑树

3.1红黑树的节点

3.2红黑树的框架

3.3set的框架

3.4map的模版

 3.5仿函数

4、迭代器

4.1迭代器的定义

4.2解引用

4.3成员访问操作符

4.4迭代器的等于和不等于

4.5迭代器的++重载

4.6迭代器的--重载

4.7红黑树的迭代器

4.8set的迭代器

4.9map的迭代器

5、总代码

5.1set的代码

5.2map的代码

5.3红黑树的代码


1、前言

在标准库中set和map的底层是通过红黑树实现的。但set是key类型的容器,而map是<key,value>类型的容器,那我们是用key和<key,value>的两棵树分别去实现set和map,还是只需要用一棵树去实现呢?

2、通过源码进行分析

从上面的源码中我们可以看到:set和map中的模版参数都包含key_type和value_type,但在set中这两个参数的本质都是key,而在map中key_type和value_type却分别代表着key和pair

通过红黑树节点所存的数据类型我们可以清楚地知道这棵树是set还是map是由value_type来控制的,因此一棵泛型结构的红黑树,通过不同实例化参数分别构造set和map

3、泛型红黑树

3.1红黑树的节点

enum Color
{Red,Black
};template<class T> //使用模版参数,通过实例化确定里面存储的是key还是pair
struct RBTreeNode
{RBTreeNode(const T& val = T(),Color col = Red):_parent(nullptr),_left(nullptr),_right(nullptr),_val(val),_col(col){ }RBTreeNode* _parent;RBTreeNode* _left;RBTreeNode* _right;T _val;Color _col;
};

3.2红黑树的框架

template<class K, class T>
class RBTree
{typedef RBTreeNode<T> Node; //对于模版参数T,它可以为Key也可以是pair,通过具体的实例化来确定是set还是map
private:Node* _root = nullptr;
};

3.3set的框架

template<class K>
class set
{
public:
private:RBTree<K, K> _t; //set传给泛型红黑树的就是<K,K>
};

3.4map的模版

template<class K,class V>
class map
{
public:
private:RBTree<K, pair<const K, V>> _t; //map传给泛型红黑树的就是<K,pair<K,V>>
};

 3.5仿函数

由于set和map是通过泛型红黑树来进行实现的,它的底层也是个搜索树,因此它需要比较大小对于set,它是个key类型可以直接进行比较,但是对于map,它却是个pair<K,V>类型,虽然库中写了pair的比较,但却并不符合我们的需要,我们需要通过pair的first来比较大小,因此我们需要写一个仿函数来帮助我们解决这一问题,因此该泛型红黑树需要第三个模版参数来接受set和map所对应的仿函数,代码如下:

红黑树的框架:

template<class K, class T, class KeyofT> //第三个模版参数从T中提取key
class RBTree
{typedef RBTreeNode<T> Node; 
private:Node* _root = nullptr;
};

set加入仿函数后的框架:

template<class K>
class set
{
public:struct SetKeyofT{const K& operator()(const K& key) //对于set来说仅仅是个形式{return key;}};	
private:RBTree<K, K, SetKeyofT> _t;
};

map加入仿函数后的框架:

template<class K,class V>
class map
{
public:struct MapKeyofT{const K& operator()(const pair<K, V>& data) //对于map需要提取key(即pair的first)进行比较{return data.first;}};
private:RBTree<K, pair<const K, V>, MapKeyofT> _t;
};

因此我们的红黑树在查找部分就可以直接通过仿函数来实现了,代码如下:

Node* parent = nullptr;
Node* cur = _root;
KeyofT kot;
while (cur)
{parent = cur;if (kot(val) > kot(cur->_val)){cur = cur->_right;}else if (kot(val) < kot(cur->_val)){cur = cur->_left;}else{return false;}
}
cur = new Node(val);
if (kot(cur->_val) > kot(parent->_val))
{parent->_right = cur;
}
else
{parent->_left = cur;
}
cur->_parent = parent;

4、迭代器

4.1迭代器的定义

template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{typedef RBTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){ }
};

4.2解引用

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

4.3成员访问操作符

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

4.4迭代器的等于和不等于

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

4.5迭代器的++重载

  1. 右不为空时,此时++就需要去找右子树的最左节点
  2. 右为空时,此时已经走过了左树,且根节点就是当前节点,因此需要向上走去找孩子是父亲左树的那个祖先(即cur == parent->left)
Self& operator++()
{if (_node->_right) //右存在,则下一个节点就是右子树的最左节点{Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else //右不存在{//左 根 右Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur) //右不存在,当前为根,左边已经走过,因此需要向上走,直到未走过的根节点//而这个根节点parent和cur的关系为parent->_left == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}

4.6迭代器的--重载

  1. 左存在时,需要去找左子树的最右节点
  2. 左不存在时,右走过,当前为根,因此需要向上走,直到走到孩子是父亲右的祖先,即这个父节点parent和cur的关系为parent->_right == cur
Self& operator--()
{// 左 根 右if (_node->_left) //左存在,当前为根,下一个节点就是左子树的最右节点{Node* cur = _node->_left;while (cur->_right){cur = cur->_right;}_node = cur;}else //左不存在{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur)//左不存在,右走过,当前为根,因此需要向上走,直到找到孩子是父亲右的祖先//而这个根节点parent和cur的关系为parent->_right == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}

4.7红黑树的迭代器

typedef __RBTreeIterator<T, T&, T*> iterator;
typedef __RBTreeIterator<T, const T&, const T*> const_iterator;
iterator begin()
{Node* cur = _root;while (cur->_left){cur = cur->_left;}return iterator(cur);
}
iterator end()
{return iterator(nullptr);
}
const_iterator begin()const
{Node* cur = _root;while (cur->_left){cur = cur->_left;}return const_iterator(cur);
}
const_iterator end()const
{return const_iterator(nullptr);
}

4.8set的迭代器

typedef typename RBTree<K, K, SetKeyofT>::const_iterator iterator; //set的key不能修改,因此都是const迭代器
typedef typename RBTree<K, K, SetKeyofT>::const_iterator const_iterator;iterator begin()const
{return _t.begin();
}
iterator end()const
{return _t.end();
}

4.9map的迭代器

template<class K,class V>
class map
{
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();}
private:RBTree<K, pair<const K, V>, MapKeyofT> _t; //map的key不可以修改,value可以修改,因此需要const修饰key
};

5、总代码

5.1set的代码

namespace asd //避免与库中的set冲突,需要命名空间
{template<class K>class set{public:struct SetKeyofT{const K& operator()(const K& key){return key;}};typedef typename RBTree<K, K, SetKeyofT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyofT>::const_iterator const_iterator;iterator begin()const{return _t.begin();}iterator end()const{return _t.end();}bool insert(const K& key){return _t.insert(key);}private:RBTree<K, K, SetKeyofT> _t;};
}

5.2map的代码

namespace ads
{template<class K,class V>class map{public:struct MapKeyofT{const K& operator()(const pair<K, V>& data){return data.first;}};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();}bool insert(const pair<const K, V>& data){return _t.insert(data);}private:RBTree<K, pair<const K, V>, MapKeyofT> _t;};
}

5.3红黑树的代码

enum Color
{Red,Black
};
template<class T>
struct RBTreeNode
{RBTreeNode(const T& val = T(),Color col = Red):_parent(nullptr),_left(nullptr),_right(nullptr),_val(val),_col(col){ }RBTreeNode* _parent;RBTreeNode* _left;RBTreeNode* _right;T _val;Color _col;
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{typedef RBTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){ }Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}Self& operator++(){if (_node->_right) //右存在,则下一个节点就是右子树的最左节点{Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else //右不存在{//左 根 右Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur) //右不存在,当前为根,左边已经走过,因此需要向上走,直到未走过的根节点,//而这个根节点parent和cur的关系为parent->_left == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self& operator--(){// 左 根 右if (_node->_left) //左存在,当前为根,下一个节点就是左子树的最右节点{Node* cur = _node->_left;while (cur->_right){cur = cur->_right;}_node = cur;}else //左不存在{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur)//左不存在,右走过,当前为根,因此需要向上走,直到未走过的节点,//而这个根节点parent和cur的关系为parent->_right == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;}bool operator!=(const Self& s){return _node != s._node;}bool operator==(const Self& s){return _node == s._node;}
};template<class K, class T, class KeyofT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef __RBTreeIterator<T, T&, T*> iterator;typedef __RBTreeIterator<T, const T&, const T*> const_iterator;iterator begin(){Node* cur = _root;while (cur->_left){cur = cur->_left;}return iterator(cur);}iterator end(){return iterator(nullptr);}const_iterator begin()const{Node* cur = _root;while (cur->_left){cur = cur->_left;}return const_iterator(cur);}const_iterator end()const{return const_iterator(nullptr);}bool insert(const T& val){if (_root == nullptr){_root = new Node(val);_root->_col = Black;return true;}else{Node* parent = nullptr;Node* cur = _root;KeyofT kot;while (cur){parent = cur;if (kot(val) > kot(cur->_val)){cur = cur->_right;}else if (kot(val) < kot(cur->_val)){cur = cur->_left;}else{return false;}}cur = new Node(val);if (kot(cur->_val) > kot(parent->_val)){ parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//往下都是对红黑树的调整以及检查是否是红黑树的代码while (parent && parent->_col == Red){Node* grandparent = parent->_parent;if (grandparent->_left == parent){Node* uncle = grandparent->_right;if (uncle && uncle->_col == Red){grandparent->_col = Red;parent->_col = uncle->_col = Black;//继续向上检查cur = grandparent;parent = cur->_parent;}else //(uncle == nullptr || uncle->_col == Black){//cur是parent的左孩子,单旋调整if (cur == parent->_left){RotateR(grandparent);parent->_col = Black;grandparent->_col = Red;}else //cur是parent的右孩子,双旋调整{RotateL(parent);RotateR(grandparent);cur->_col = Black;grandparent->_col = Red;}break;}}else{Node* uncle = grandparent->_left;if (uncle && uncle->_col == Red){grandparent->_col = Red;parent->_col = uncle->_col = Black;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = Black;grandparent->_col = Red;}else{RotateR(parent);RotateL(grandparent);cur->_col = Black;grandparent->_col = Red;}break;}}}_root->_col = Black;            return true;}}bool IsBalance(){return _IsBalance(_root);}int Height(){return _Height(_root);}
private: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->_val << "出现连续红色节点" << endl;return false;}return CheckColour(root->_left, blacknum, benchmark)&& CheckColour(root->_right, blacknum, benchmark);}bool _IsBalance(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);}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 RotateR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;Node* pparent = parent->_parent;parent->_left = sublr;if (sublr)sublr->_parent = parent;subl->_right = parent;parent->_parent = subl;if (_root == parent){_root = subl;subl->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = subl;}else{pparent->_right = subl;}subl->_parent = pparent;}}void RotateL(Node* parent){Node* subr = parent->_right;Node* subrl = subr->_left;parent->_right = subrl;subr->_left = parent;Node* pparent = parent->_parent;parent->_parent = subr;if (subrl)subrl->_parent = parent;if (_root == parent){_root = subr;subr->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = subr;}else{pparent->_right = subr;}subr->_parent = pparent;}}Node* _root = nullptr;
};
http://www.dtcms.com/a/536277.html

相关文章:

  • Python机器学习---7.实战案例:幸福指数分析
  • 大型网站建设淮安公司网站建设
  • 重庆简约型网站开发价格做教程网站资源放哪里有
  • axios封装实例
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段-二阶段(8):阶段复习
  • RabbitMQ死信队列详解
  • 信息消除不确定性的多维解析
  • Day12:Python实现邮件自动发送
  • 点亮LED
  • 家乡ppt模板免费下载网站地图 添加到网站
  • JMeter直连数据库的使用案例1
  • 网站备案ip查询系统上海十大营销策划公司排名
  • STM32H743-ARM例程31-CAN
  • Claude Code + 国产模型GLM-4.6 安装指南 (for Windows/Mac)
  • Docker 镜像导出与导入教程(Windows - Linux)
  • ARM《4》_在开发板上裸机编程实现GPIO编程控制LED灯闪烁
  • 手机商城 手机网站建设郴州今天几例
  • 从 Electron 转向 Tauri:用 Rust 打造更轻、更快的桌面应用
  • webrtc代码走读(九)-QOS-SVC(可分级视频编码)
  • 个人项目开发(3) 实现基于角色的权限控制及自动刷新token
  • 在柬埔寨做网络销售推网站校园网站建设教程
  • 具备高度自主学习能力、互联网交互能力、智能家居控制能力和多模态交互能力的通用智能体原型系统
  • 爬虫前奏--基于macos的ip代理池构建
  • 网站开发专员的面试题微信导航wordpress
  • 给传销做网站网站设计模板psd
  • Kingbase 与 ETL:如何实现金融级数据库的安全数据同步
  • cocos 用widget将ui组件固定在屏 随着分辨率自适应 编辑器界面canvas作为手机屏参考 将ui组件放进去 deepseek解答
  • 《微信小程序》第六章:参数定义与管理
  • ElasticSearch架构和写入、更新、删除、查询的底层逻辑
  • 做市场调研的网站网站建设费可以计入管理费用吗