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

news2024/11/18 21:51:32

目录

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

①红黑树的迭代器

②红黑树的改造

2.map的模拟实现

3.set的模拟实现

4.测试


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
							//cur
							RotateR(grandpa);
							grandpa->_color = RED;
							parent->_color = BLACK;
						}
						else
						{
							//              grandpa
							//      parent
							//              cur
							RotateL(parent);
							RotateR(grandpa);
							cur->_color = BLACK;
							grandpa->_color = RED;
						}
					}
					else // uncle存在且为黑
					{
						if (parent->_left == cur)
						{
							//              grandpa
							//      parent
							//cur
							RotateR(grandpa);
							grandpa->_color = RED;
							parent->_color = BLACK;
						}
						else
						{
							//              grandpa
							//      parent
							//              cur
							RotateL(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
							//cur
							RotateR(parent);
							RotateL(grandpa);
							cur->_color = BLACK;
							grandpa->_color = RED;
						}
						else
						{
							//grandpa
							//        parent
							//               cur
							RotateL(grandpa);
							grandpa->_color = RED;
							parent->_color = BLACK;
						}
					}
					else // uncle存在且为黑
					{
						if (parent->_left == cur)
						{
							//grandpa
							//         parent
							//cur
							RotateR(parent);
							RotateL(grandpa);
							cur->_color = BLACK;
							grandpa->_color = RED;
						}
						else
						{
							//grandpa
							//        parent
							//               cur
							RotateL(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.coloradmin.cn/o/1065014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ubuntu增加内存

文章目录 1、硬盘操作步骤第二步:点击【扩展】(必须关闭ubuntu电源才能修改)第三步:修改【最大磁盘容量大小】1、硬盘操作步骤 最近发现Ubuntu空间不足,怎么去扩容呢? 第一步:点击【硬盘】 第二步:点击【扩展】(必须关闭ubuntu电源才能修改) 第三步:修改【最大磁…

Java反序列化:CC1链 详解

CC1 Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库&#xff0c;它提供了很多强大的数据结构类型和实现了各种集合工具类。作为Apache开放项目的重要组件&#xff0c;Commons Collections被广泛的各种Java应用的开发&#xff0c;⽽正 是因…

腾讯云轻量和CVM有啥区别?怎么选择服务器配置?

腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器价格便宜&#xff1f;是因为轻量服务器CPU内存性能比云服务器CVM性能差吗&#xff1f;轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境&#xff0c;云服务器CV…

MIPI接口协议及规范理解

什么是MIPI接口 MIPI&#xff0c;英文全称为Mobile Industry Processor Interface&#xff0c;即移动行业处理器接口。它是MIPI联盟发起的为移动应用处理器制定的开放标准。MIPI接口是一种专为移动设备和嵌入式系统设计的串行通信接口&#xff0c;定义了一系列的接口标准&…

【pwn入门】用gdb调试32位程序

声明 本文是B站你想有多PWN学习的笔记&#xff0c;包含一些视频外的扩展知识。 问题源码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> char sh[]"/bin/sh"; int func(char *cmd){system(cmd);return 0; }int main(){char a[8]…

学习搜狗的workflow,MacBook上如何编译

官网说可以在MacBook上也可以运行&#xff0c;但是编译的时候却有找不到openssl的错误&#xff1a; 看其他博客也有类似的错误&#xff0c;按照类似的思路去解决 问题原因和解决办法 cmake编译的时候&#xff0c;没有找到openssl的头文件&#xff0c;需要设置cmake编译环境下…

基于Java的连锁超市会员管理系统设计与实现(源码+lw+ppt+部署文档+视频讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

孢子捕捉仪——植物疾病探测的得力工具

孢子捕捉仪是一款专为收集随空气流动、传染的病害病原菌孢子及花粉尘粒而制的精密仪器&#xff0c;它主要用于监测病害孢子的存量及其扩散动态&#xff0c;犹如植物健康状况的“超级侦察兵”&#xff0c;是农业植保部门应当配备的农作物病害监测专用设备&#xff0c;是植物疾病…

学之思第二天-调通登录功能

目录 一、前端问题 二、后端问题 三、总结 之前一直是一个前端网页即使输对了正确的账号密码&#xff0c;也进不去。 一、前端问题 前端控制台就是一大堆爆红&#xff1a; 报错信息大概下面这样&#xff1a; Uncaught (in promise) NavigationDuplicated {_name: "…

Uniapp 婚庆服务全套模板前端

包含 首页、社区、关于、我的、预约、订购、选购、话题、主题、收货地址、购物车、系统通知、会员卡、优惠券、积分、储值金、订单信息、积分、充值、礼品、首饰等 请观看 图片参观 开源&#xff0c;下载即可 链接&#xff1a;婚庆服务全套模板前端 - DCloud 插件市场 问题反…

QT:SQLITE数据库编程

pro文件&#xff1a;QT core gui sql widget.ui main.cpp #include "widget.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w("./student.db"); //传入文件名w.show();return a.exec…

binary_cross_entropy和binary_cross_entropy_with_logits的区别

binary_cross_entropy和binary_cross_entropy_with_logits的区别 引言 二分类问题是常见的机器学习任务之一&#xff0c;其目标是将样本分为两个类别。为了训练一个二分类模型&#xff0c;通常使用交叉熵作为损失函数。 二分类交叉熵损失函数有两种不同的形式&#xff0c;分…

深度学习之人脸检测算法

检测方法&#xff1a; Haar cascade opencv HOG Dlib CNN Dlib SSD MTCNN Haar特征 1.Haar特征原理综述 Haar特征是一种反映图像的灰度变化的&#xff0c;像素分模块求差值的一种特征。它分为三类&#xff1a;边缘特征、线性特征、中心特征和对角线特征。用黑白两种…

EQ 均衡器

EQ 的全称是 Equalizer&#xff0c;EQ 是 Equalizer 的前两个字母&#xff0c;中文名字叫做“均衡器”。最早是用来提升电话信号在长距离的传输中损失的高频&#xff0c;由此得到一个各频带相对平衡的结果&#xff0c;它让各个频带的声音得到了均衡。 EQ 的主要功能是&#xf…

端口隔离 MAC地址安全配置

二、知识点 目前网络中以太网技术的应用非常广泛。然而&#xff0c;各种网络攻击的存在&#xff08;例如针对ARP、DHCP等协议的攻击&#xff09;&#xff0c;不仅造成了网络合法用户无法正常访问网络资源&#xff0c;而且对网络信息安全构成严重威胁&#xff0c;因此以太网交…

学习笔记|串口通信的基础知识|同步/异步|常见的串口软件的参数|STC32G单片机视频开发教程(冲哥)|第二十集:串口通信基础

目录 1.串口通信的基础知识串口通信(Serial Communication)同步/异步&#xff1f;全双工&#xff1f;常见的串口软件的参数 2.STC32的串口通信实现原理引脚选择模式选择 3.串口通信代码实现编写串口1通信程序测试 总结 1.串口通信的基础知识 百度百科&#xff1a;串口通信的概…

STM32F103C8t SPI1重映射到PB3 PB4 PB5无输出

STM32F103C8t6用到了ADC 和SPI 导致PAx口无法使用SPI1 因此像复用到的引脚&#xff0c; 检查后发现硬件SPI可以复用到PB3 PB4 PB5&#xff0c; MSIO&#xff1a;PB5 MOSI&#xff1a;PB4 SCK&#xff1a;PB3 但是尝试后发现没有反映 SCK引脚没有波形输出 GPIO_PinRemapConfig(…

使用pywin32读取doc文档的方法及run输出乱码 \r\x07

想写一个读取doc文档中表格数据&#xff0c;来对文档进行重命名。经查资料&#xff0c;py-docx无法读取doc文档&#xff0c;原因是这种是旧格式。所以&#xff0c;采用pywin32来进行读取。 import win32com.client as win32word win32.gencache.EnsureDispatch(Word.Applicati…

Fiddler的下载安装及使用(包括在测试中的使用)

一、Fiddler的下载安装 1.Fiddler的介绍 1.1 Fiddler的定义和功能 Fiddler是一款免费网络代理调试工具。 Fiddler是一个很好用的抓包工具&#xff0c; 可以将网络传输发送与接受的数据包进行截获、重发、编辑、转存等操作。 也可以用来检测网络安全。 1.2 Fiddler的工作原理…

JUC第十六讲:JUC集合: CopyOnWriteArrayList详解

JUC第十六讲&#xff1a;JUC集合: CopyOnWriteArrayList详解 本文是JUC第十六讲&#xff0c;JUC集合: CopyOnWriteArrayList详解。CopyOnWriteArrayList是ArrayList 的一个线程安全的变体&#xff0c;其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的拷贝来实现…