C++库函数——set与map的模拟实现

1.红黑树的迭代器与改造

①红黑树的迭代器

对于上面这棵红黑树,我们可以很容易得知道begin()是红黑树的最左节点,end()应该是一个空节点。即

iterator begin()
{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return cur;
}iterator end()
{return iterator(nullptr);
}

 接下来定义iterator及其具体操作

template<class T>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T> Self;RBTreeIterator(Node* node): _node(node){}// 让迭代器具有类似指针的行为T& operator*(){return _node->_data;}T* 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;}if (parent && cur == parent->_left)_node = parent;else_node = nullptr;}return *this;}Self operator++(int){Self tmp(*this);++(*this);return tmp;}// 迭代器可以移动:前置/后置-- Self& operator--(){// 这里的大致逻辑与++类似if (_node->_left){_node = _node->_left;while (_node->_right){_node = _node->_right;}}else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}if (parent && cur == parent->_right)_node = parent;else_node = nullptr;}return *this;}Self operator--(int){Self tmp(*this);--(*this);return tmp;}// 让迭代器可以比较bool operator!=(const Self& s)const{return _node != s._node;}bool operator==(const Self& s)const{return _node == s._node;}Node* _node;
};

②红黑树的改造

// set->RBTree<K, K, SetKeyOfT> _t;
// map->RBTree<K, pair<K, V>, MapKeyOfT> _t;
template<class K, class T, class KeyofT>
class RBTree
{
public:typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, T*, T&> iterator;typedef RBTreeIterator<T, const T*, const T&> const_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);}Node* Find(const T& data){KeyofT kot;Node* cur = _root;while (cur){if (kot(data) < kot(cur->_data)){cur = cur->_left;}else if (data > kot(cur->_data)){cur = cur->_right;}else{return cur;}}return nullptr;}pair<iterator, bool> Insert(const T& data){KeyofT kot;if (_root == nullptr){_root = new Node(data);_root->_color = BLACK;return make_pair((iterator)_root, true);}Node* cur = _root;Node* parent = nullptr;// 寻找要插入的位置while (cur){if (kot(data) < kot(cur->_data)){parent = cur;cur = cur->_left;}else if (kot(data) > kot(cur->_data)){parent = cur;cur = cur->_right;}else{return make_pair((iterator)cur, false);}}// 到此处cur已经指向了应该插入的位置,// 然后判断应该插入到parent的哪边cur = new Node(data);if (kot(data) > kot(parent->_data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;// 插入完成后判断一下// 若父节点是黑就无需调整// 而当父节点是红就需要进行调整while (parent && parent->_color == RED){Node* grandpa = parent->_parent;if (parent == grandpa->_left){Node* uncle = grandpa->_right;if (uncle && uncle->_color == RED){uncle->_color = parent->_color = BLACK;grandpa->_color = RED;cur = grandpa;parent = cur->_parent;}else{if (uncle == nullptr){if (parent->_left == cur){//              grandpa//      parent//curRotateR(grandpa);grandpa->_color = RED;parent->_color = BLACK;}else{//              grandpa//      parent//              curRotateL(parent);RotateR(grandpa);cur->_color = BLACK;grandpa->_color = RED;}}else // uncle存在且为黑{if (parent->_left == cur){//              grandpa//      parent//curRotateR(grandpa);grandpa->_color = RED;parent->_color = BLACK;}else{//              grandpa//      parent//              curRotateL(parent);RotateR(grandpa);cur->_color = BLACK;grandpa->_color = RED;}}break;}}else // parent == grandpa->_right{Node* uncle = grandpa->_left;if (uncle && uncle->_color == RED){uncle->_color = parent->_color = BLACK;grandpa->_color = RED;cur = grandpa;parent = cur->_parent;}else{if (uncle == nullptr){if (parent->_left == cur){//grandpa//         parent//curRotateR(parent);RotateL(grandpa);cur->_color = BLACK;grandpa->_color = RED;}else{//grandpa//        parent//               curRotateL(grandpa);grandpa->_color = RED;parent->_color = BLACK;}}else // uncle存在且为黑{if (parent->_left == cur){//grandpa//         parent//curRotateR(parent);RotateL(grandpa);cur->_color = BLACK;grandpa->_color = RED;}else{//grandpa//        parent//               curRotateL(grandpa);grandpa->_color = RED;parent->_color = BLACK;}}break;}}}if (cur->_parent == nullptr){cur->_color = BLACK;}return make_pair((iterator)cur, true);}void RotateL(Node* parent){Node* cur = parent->_right;    // 记录当前节点Node* curleft = cur->_left; // 记录当前节点的左节点// 如果当前节点的左节点为空说明是h为0的情况// 不为空时就要进行节点间的连接if (curleft){curleft->_parent = parent;}parent->_right = curleft;cur->_left = parent;// 此时需要确定parent是否属于子树if (parent == _root){_root = cur;cur->_parent = nullptr;}else // 此时parent以下的节点属于子树{cur->_parent = parent->_parent;// 确认parent与其父节点间的关系// 然后将cur与parent的父节点连接起来if (parent->_parent->_left == parent){parent->_parent->_left = cur;}else{parent->_parent->_right = cur;}}parent->_parent = cur;}void RotateR(Node* parent){Node* cur = parent->_left;    // 记录当前节点Node* curright = cur->_right; // 记录当前节点的右节点// 如果当前节点的右节点为空说明是h为0的情况// 不为空时就要进行节点间的连接if (curright){curright->_parent = parent;}parent->_left = curright;cur->_right = parent;// 此时需要确定parent是否属于子树if (parent == _root){_root = cur;cur->_parent = nullptr;}else // 此时parent以下的节点属于子树{cur->_parent = parent->_parent;// 确认parent与其父节点间的关系// 然后将cur与parent的父节点连接起来if (parent->_parent->_left == parent){parent->_parent->_left = cur;}else{parent->_parent->_right = cur;}}parent->_parent = cur;}private:Node* _root = nullptr;
};

2.map的模拟实现

namespace my_map
{template<class K, class V>class map{struct MapKeyOfT{const K& operator()(const pair<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();}V& operator[](const K& key){pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};
}

3.set的模拟实现

namespace my_set
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public: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();}// 使用iterator RBTree::const_iterator时,有// 无法从“std::pair<RBTreeIterator<T,T *,T &>,bool>”// 转换为“std::pair<RBTreeIterator<T,const T *,const T &>,bool>”// pair<iterator, bool> insert(const K& key)// {//		return _t.Insert(key);// }pair<iterator, bool> insert(const K& key){// 将插入后的结果用一个key类型的pair接收pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);// 用ret的的元素构造key的特定pair// 目的:这里的iterator实际是const_iterator, // 转换之后可以使key的第一个元素不被修改return pair<iterator, bool>(ret.first, ret.second);}private:RBTree<K, K, SetKeyOfT> _t;};
}

4.测试

#include "my_map.h"
#include <map>
#include <set>
#include "my_set.h"//int main()
//{
//	RBTree<int, int, pair<int, int>> t;
//	for (int i = 0; i < 100; i++)
//	{
//		t.Insert(i);
//	}
//
//	RBTree<int, int, pair<int, int>>::iterator it = t.begin();
//	while (it != t.end())
//	{
//		cout << *it << " ";
//		it++;
//	}
//
//	return 0;
//}//int main()
//{
//	my_set::set<int> st;
//	for (int i = 0; i < 10; i++)
//	{
//		st.insert(i);
//	}
//
//	auto it = st.begin();
//	while (it != st.end())
//	{
//		cout << *it << " ";
//		++it;
//	}
//
//	return 0;
//}//int main()
//{
//	my_set::set<int> st;
//	for (int i = 0; i < 10; i++)
//	{
//		st.insert(i);
//	}
//
//	my_set::set<int>::iterator it = st.begin();
//	while (it != st.end())
//	{
//		//if (*it % 2 == 0)
//		//{
//		//	*it += 10;
//		//}
//		cout << *it << " ";
//		++it;
//	}
//
//	return 0;
//}//int main()
//{
//	my_map::map<string, string> st;
//	string s1 = "a";
//	string s2 = "b";
//	for (int i = 0; i < 10; i++)
//	{
//		st.insert(make_pair(s1, s2));
//		s1[0]++;
//		s2[0]++;
//	}
//
//	my_map::map<string, string>::iterator it = st.begin();
//	while (it != st.end())
//	{
//		//if (*it % 2 == 0)
//		//{
//		//	*it += 10;
//		//}
//		cout << (*it).first << ":"<< (*it).second << " "<<endl;
//		++it;
//	}
//
//	return 0;
//}int main()
{my_map::map<string, string> dict;dict.insert(make_pair("sort", "xxx"));dict["left"]; // 插入for (const auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}cout << endl;dict["left"] = "左边"; // 修改dict["sort"] = "排序"; // 修改dict["right"] = "右边"; // 插入+修改for (const auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}cout << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/125934.html

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

相关文章

蓝桥杯---第二讲---二分与前缀和

文章目录 前言Ⅰ. 数的范围0x00 算法思路0x00 代码书写 Ⅱ. 数的三次方根0x00 算法思路0x01代码书写 Ⅲ. 前缀和0x00 算法思路0x01 代码书写 Ⅳ. 子矩阵的和0x00 算法思路0x01 代码书写 Ⅴ. 机器人跳跃问题0x00 算法思路0x01 代码书写 Ⅵ. 四平方和0x00 算法思路0x01 代码书写 …

创意中秋与国庆贺卡 - 用代码为节日增添喜悦

目录 ​编辑 引言 贺卡的初始主题 - 中秋节 点击头像&#xff0c;切换至国庆主题 文本动画 用代码制作这个贺卡 获取完整代码&#xff08;简单免费&#xff09; 总结 引言 中秋佳节和国庆日是中国两个重要的传统节日&#xff0c;一个寓意团圆与祝福&#xff0c;另一个…

【AI视野·今日NLP 自然语言处理论文速览 第四十七期】Wed, 4 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 4 Oct 2023 Totally 73 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Contrastive Post-training Large Language Models on Data Curriculum Authors Canwen Xu, Corby Rosset, Luc…

节日灯饰灯串灯出口欧洲CE认证办理

灯串&#xff08;灯带&#xff09;&#xff0c;这个产品的形状就象一根带子一样&#xff0c;再加上产品的主要原件就是LED&#xff0c;因此叫做灯串或者灯带。2022年&#xff0c;我国灯具及相关配件产品出口总额超过460亿美元。其中北美是最大的出口市场。其次是欧洲市场&#…

leetCode 45.跳跃游戏 II 贪心算法

45. 跳跃游戏 II - 力扣&#xff08;LeetCode&#xff09; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 &…

剑指offer——JZ26 树的子结构 解题思路与具体代码【C++】

一、题目描述与要求 树的子结构_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入两棵二叉树A&#xff0c;B&#xff0c;判断B是不是A的子结构。&#xff08;我们约定空树不是任意一个树的子结构&#xff09; 假如给定A为{8,8,7,9,2,#,#,#,#,4,7}&#xff0c;B为{8,9,2}&…

生产设备巡检管理系统

凡尔码搭建生产设备巡检系统是通过确保巡检工作的质量以及提高巡检工作的效率来提高设备维护水平的一种系统&#xff0c;它对巡检管理考核工作从巡检人员、巡检任务、隐患管理、图像视频、盯防考核进行严格、科学的统计、分析&#xff0c;从而有效的保障巡检工作的顺利展开&…

超声波气象站——环境监测领域强大助手

超声波气象站是环境监测领域的一位强大助手&#xff0c;超声波气象站是一种综合型的气象设备&#xff0c;精巧而全面&#xff0c;满足人们对环境状况的深入了解和精准把握。 首先&#xff0c;超声波气象站的传感器部分&#xff0c;是它的核心组成部分&#xff0c;这位“感知者”…

【数据结构】排序(3)—堆排序归并排序

目录 一. 堆排序 基本思想 代码实现 向上调整算法 向下调整算法 时间和空间复杂度 稳定性 二. 归并排序 基本思想 代码实现 时间和空间复杂度 稳定性 一. 堆排序 堆排序&#xff08;Heapsort&#xff09;是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似 …

蓝桥等考Python组别十四级002

第一部分&#xff1a;选择题 1、Python L14 &#xff08;15分&#xff09; 运行下面程序&#xff0c;输出的结果是&#xff08; &#xff09;。 d {A: 11, B: 12, C: 13, D: 14} print(d[B]) 11121314 正确答案&#xff1a;B 2、Python L14 &#xff08;15分&#x…

JMeter性能测试

性能测试前言 老师开局一句话&#xff1a;性能测试和你会不会JMeter一点关系没有…… 作者坚持技多不压身的原则&#xff0c;还是多学一点JMeter吧&#xff0c;看老师到底要怎么讲下去&#xff0c;什么并发量、吞吐量啥的…… 性能测试的核心思想&#xff1a;在于创造大量并发去…

(32)测距仪(声纳、激光雷达、深度摄影机)

文章目录 前言 32.1 单向测距仪 32.2 全向性近距离测距仪 32.3 基于视觉的传感器 前言 旋翼飞机/固定翼/无人车支持多种不同的测距仪&#xff0c;包括激光雷达&#xff08;使用激光或红外线光束进行距离测量&#xff09;、360 度激光雷达&#xff08;可探测多个方向的障碍…