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

map与set封装

封装map和set一般分为6步:

1.封装map与set

2.普通迭代器

3.const 迭代器

4.insert返回值处理

5.map operator【】

6.key不能修改的问题

一.红黑树的改造 

map与set的底层是通过红黑树来封装的,但是map与set的结点储存的值不一样,set只需要存储<key,key>,而map中存储的是<key,pair<key,value>>,当我们需要比较结点之间的值时往往是通过value来进行比较,所以我们可以使用一个仿函数来取出map与set中的value值进行比较。

二.红黑树的迭代器

2.1用结点封装迭代器

我们通过红黑树的结点来对迭代器进行实现,首先我们需要三个模板参数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* _root;_TreeIterator(Node* node, Node* root):_node(node),_root(root){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self& operator++(){if (_node->_right){_node = _node->_right;while (_node->_left){_node = _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 == nullptr){Node* rightmost = _root;while (rightmost && rightmost->_right){rightmost = rightmost->_right;}_node = rightmost;}else if (_node->_left){_node = _node->_left;while (_node && _node->_right){_node = _node->_right;}}else{Node* cur = _node;Node* parent = _node->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}bool operator!=(const Self& s){return _node != s._node;}bool operator==(const Self& s){return _node == s._node;}
};

我们重载运算符*和->返回结点的data值。

迭代器遍历++时,原先的树是按照大的在右小的在左的大小进行排序,所以++时,若结点右子树存在,先遍历到第一个右结点(保证了比当前结点的值大),再向左遍历到空结点(保证了是比当前结点大的最小结点值)。若右结点不存在,且当前结点在右子树,就遍历到当前右子树的根结点,返回当前根结点的父结点即为最终值。

 红色为起始点,蓝色为最终点,当右结点不为空时的情况

红色为起始结点,蓝色为最终结点,当右结点为空时的情况。 

2.2迭代器实现 

Iterator Begin()
{Node* minleft = _root;while (minleft && minleft->_left){minleft = minleft->_left;}return Iterator(minleft, _root);
}Iterator End()
{return Iterator(nullptr, _root);
}Const_Iterator Begin() const
{Node* minleft = _root;while (minleft && minleft->_left){minleft = minleft->_left;}return Const_Iterator(minleft, _root);
}Const_Iterator End() const
{return Const_Iterator(nullptr, _root);
}

迭代器使用中序遍历的方式执行,begin从最左端开始

2.3map与set迭代器

set迭代器

typedef typename RBTree<K, const K, SetKetOft>::Iterator iterator;
typedef typename RBTree<K, const K, SetKetOft>::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();
}

_t为红黑树结构

map迭代器

typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator 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();
}

三.insert返回值

3.1insert返回值的用处

在map的operator【】中可以看到,他的返回值是通过insert来实现的,这就决定了insert的返回值必须是一个pair<iterator,bool> ,插入一个结点若key已经存在就返回false,若key不存在就返回迭代器以及true。其中在比较两者data数时需要套上一层仿函数取出pair中的值进行比较,保证pair不会走默认比较。

pair<Iterator,bool> Insert(const T& data)
{if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return { Iterator(_root,_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 { Iterator(cur,_root),false }}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){//   g// p   uNode* uncle = grandfather->_right;// 叔叔存在且为红if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLgrandfather->_col = RED;// 继续往上处理cur = grandfather;parent = cur->_parent;}else{// 叔叔不存在或者存在且为黑//      g//   p     u//cif (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//      g//   p     u//      cRotateL(parent);RotateR(grandfather);grandfather->_col = RED;cur->_col = BLACK;}break;}}else{   //   g// u   pNode* uncle = grandfather->_left;// 叔叔存在且为红,-》变色即可if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLgrandfather->_col = RED;// 继续往上处理cur = grandfather;parent = cur->_parent;}else // 叔叔不存在,或者存在且为黑{// 情况二:叔叔不存在或者存在且// 旋转+变色//      g//   u     p//            cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//      g//   u     p//      cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return { Iterator(newnode,_root),true };
}

希望各位大佬多多支持!!!

相关文章:

  • 项目QT+ffmpeg+rtsp(三)——延迟巨低的项目+双屏显示
  • mysql故障排查与环境优化
  • 使用 Whisper 生成视频字幕:从提取音频到批量处理
  • 力扣面试150题--从前序与中序遍历序列构造二叉树
  • 九、异形窗口
  • Flask 与 Django 服务器部署
  • Django 项目中,将所有数据表注册到 Django 后台管理系统
  • C++(24):容器类<list>
  • 学习源码?
  • cmd里可以使用npm,vscode里使用npm 报错
  • OpenCv(7.0)——银行卡号识别
  • 中山大学具身智能体高效探索与精准问答!Beyond the Destination:面向探索感知的具身问答新基准
  • std::ranges::views::stride 和 std::ranges::stride_view
  • 2025年AI与网络安全的终极博弈:冲击、重构与生存法则
  • 【OpenCV基础2】
  • Interrupt 2025 大会回顾:关于LangChain 的 AI Agent会议内容总结
  • 如何提高嵌入式软件设计的代码质量
  • 用 CodeBuddy 实现「IdeaSpark 每日灵感卡」:一场 UI 与灵感的极简之旅
  • MathType公式如何按照(1)(2)…编号
  • PYTHON训练营DAY30
  • 上昆“学馆制”10年,完成300出折子戏和20台大戏传承
  • 女子应聘文员被说“太丑”?官方回应:有关部门启动核查处置
  • 东航C919航线上新!正式投入上海虹桥—深圳航线运营
  • 博物馆书单|走进博物馆,去体验一场与文明的对话
  • 美国失去最后一个AAA评级,资产价格怎么走?美股或将触及天花板
  • 当“小铁人”遇上青浦,看00后如何玩转长三角铁三