C/C++ 进阶(7)模拟实现map/set

news2024/9/22 19:33:33

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

一、简介

map和set都是关联性容器,底层都是用红黑树写的。

特点:存的Key值都是唯一的,不重复。

map存的是键值对(Key—Value)。

set存的是键值(Key)。

二、map/set的模拟实现

map.h

#pragma once


#include <iostream>
#include "RBTree.h"
using namespace std;

template<class Key, class Value>
class map
{
	struct MapKeyOfT
	{
		const Key& operator()(const pair<Key, Value>& e)
		{
			return e.first;
		}
	};

public:
	typedef pair<Key, Value> PKV;
	typedef _RBTree_iterator<PKV, PKV*, PKV&> iterator;

	iterator begin()
	{
		return _t.begin();
	}
	iterator end()
	{
		return _t.end();
	}
	bool insert(const pair<Key, Value>& e)
	{
		return _t.insert(e);
	}
	void inorder()
	{
		_t.inorder();
	}
private:
	RBTree<Key, pair<Key, Value>, MapKeyOfT> _t;
};

set.h

#pragma once


#include "RBTree.h"

template<class Key>
class set
{
	struct SetKeyOfT
	{
		const Key& operator()(const Key& e)
		{
			return e;
		}
	};
public :
	typedef _RBTree_iterator<Key, Key*, Key&> iterator;

	iterator begin()
	{
		return _t.begin();
	}
	iterator end()
	{
		return _t.end();
	}
	bool insert(const Key& e)
	{
		return _t.insert(e);
	}
	void inorder()
	{
		_t.inorder();
	}
private:
	RBTree<Key, Key, SetKeyOfT> _t;
};

RBTree.h

#pragma once

#include<iostream>
using namespace std;


enum color
{
	Red,
	Black
};
template <class ValueTpye>
struct RBTreeNode
{
	RBTreeNode(const ValueTpye& e = ValueTpye())
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_col(Red)
		,_val(e)
	{}

	struct RBTreeNode<ValueTpye>* _left;
	struct RBTreeNode<ValueTpye>* _right;
	struct RBTreeNode<ValueTpye>* _parent;
	int _col;
	ValueTpye _val;
};

template<class ValueType, class Ptr, class Ref>
class _RBTree_iterator
{
	typedef RBTreeNode<ValueType> node;
	typedef _RBTree_iterator<ValueType, Ptr, Ref> iterator;
public:
	_RBTree_iterator(node* e)
		:_node(e)
	{}
	Ptr operator->()
	{
		return &_node->_val;
	}
	Ref operator*()
	{
		return _node->_val;
	}
	bool operator!=(iterator it)
	{
		return _node != it._node;
	}
	iterator& operator++()
	{
		if (_node->_right)
		{
			node* left = _node->_right;
			while (left->_left)
			{
				left = left->_left;
			}
			_node = left;
		}
		else
		{
			node* cur = _node;
			node* p = cur->_parent;
			while (p && cur == p->_right)
			{
				cur = p;
				p = p->_parent;
			}
			_node = p;
		}
		return *this;
	}
private:
	node* _node;
};

template <class Key, class ValueType, class KeyOfT>
class RBTree
{
public:
	typedef RBTreeNode<ValueType> node;
	typedef _RBTree_iterator<ValueType, ValueType*, ValueType&> iterator;
	KeyOfT kot;

	RBTree()
		:_root(nullptr)
	{}

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

	node* find(const Key& e)
	{
		node* cur = _root;

		while (cur)
		{
			if (kot(cur->_val).first > e)
			{
				cur = cur->_left;
			}
			else if (kot(cur->_val).first < e)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

	bool insert(const ValueType& e)
	{
		// 根据二叉搜索树插入的方式进行插入
		node* cur = _root;
		node* parent = cur;

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

		// 更新,对于不同的情况,进行不同的调整
		// parent 为黑、不存在,结束
		node* p = parent;
		while (p && p->_col == Red)
		{
			node* g = p->_parent;

			if (g->_left == p)
			{
				node* u = g->_right;
				// 叔叔存在且为红
				if (u && u->_col == Red)
				{
					p->_col = u->_col = Black;
					g->_col = Red;

					// 继续往上处理
					cur = g;
					p = cur->_parent;
				}
				// 叔叔不存在且为黑
				else 
				{
					//    g
					//  p   u
					// c
					if (cur == p->_left)
					{
						// 右单旋
						RotateR(g);

						// 变色
						g->_col = Red;
						p->_col = Black;

					}
					//    g
					//  p   u
					//    c
					else 
					{
						// 左右双旋
						RotateL(p);
						RotateR(g);

						// 变色
						cur->_col = Black;
						g->_col = Red;
					}
					// 叔叔不存在或者存在且为黑调整完,就不需要继续进行调整了
					break;
				}
			}
			else
			{
				node* u = g->_left;

				if (u && u->_col == Red)
				{
					p->_col = u->_col = Black;
					g->_col = Red;

					// 继续往上处理
					cur = g;
					p = cur->_parent;
				}
				else 
				{
					//    g
					//  u   p
					//        c
					if (cur == p->_right)
					{
						// 左单旋
						RotateL(g);

						// 变色
						g->_col = Red;
						p->_col = Black;

					}
					//    g
					//  u   p
					//    c
					else 
					{
						// 左右双旋
						RotateR(p);
						RotateL(g);

						// 变色
						cur->_col = Black;
						g->_col = Red;
					}
					// 叔叔不存在或者存在且为黑调整完,就不需要继续进行调整了
					break;
				}
			}

		}

		_root->_col = Black;

		return true;
	}


	void inorder()
	{
		_inorder(_root);
	}
private:
	void _inorder(node* root)
	{
		if (root == nullptr) return;

		_inorder(root->_left);
		cout << kot(root->_val) << " ";
		_inorder(root->_right);
	}
	void RotateR(node* parent)
	{
		node* subl = parent->_left;
		node* sublr = subl->_right;

		node* grandfather = parent->_parent;

		parent->_left = sublr;
		if (sublr)
		{
			sublr->_parent = parent;
		}

		subl->_right = parent;
		parent->_parent = subl;

		subl ->_parent = grandfather;

		if (_root == parent)
		{
			if (grandfather->_left == parent)
			{
				grandfather->_left = subl;
			}
			else
			{
				grandfather->_right = subl;
			}
		}
		else
		{
			_root = subl;
		}
	}
	void RotateL(node* parent)
	{
		node* subr = parent->_right;
		node* subrl = subr->_left;

		node* grandfather = parent->_parent;

		parent->_right = subrl;
		if (subrl)
		{
			subrl->_parent = parent;
		}

		subr->_left = parent;
		parent->_parent = subr;

		subr ->_parent = grandfather;

		if (_root != parent)
		{
			if (grandfather->_left == parent)
			{
				grandfather->_left = subr;
			}
			else
			{
				grandfather->_right = subr;
			}
		}
		else
		{
			_root = subr;
		}
	}

private:
	node* _root;
};

main.cpp(测试)

#define _CRT_SECURE_NO_WARNINGS 1

#include "map.h"
#include "set.h"
//#include <map>
//#include <set>
#include <iostream>
using namespace std;

void test1()
{
	int a[] = {5, 3, 7, 3, 7, 8, 4, 2, 9, 10};
	map<int, int> m;

	for (int e : a)
	{
		m.insert(make_pair(e, e));
	}

	m.inorder();
}

void test2()
{
	int a[] = {5, 3, 7, 3, 7, 8, 4, 2, 9, 10};
	set<int> s;

	for (int e : a)
	{
		s.insert(e);
	}

	s.inorder();
}

void test3()
{
	int a[] = {5, 3, 7, 3, 7, 8, 4, 2, 9, 10};
	set<int> s;
	for (int e : a)
	{
		s.insert(e);
	}

	auto it = s.begin();
	while (it != s.end())
	{
		cout << *it << endl;
		++ it;
	}
}

void test4()
{
	pair<int, int> a[] = {{5, 5}, {3, 3}, {7, 7}, {3, 3}, {7, 7}, {8, 8}, {4, 4}, {2, 2}, {9, 9}, {10, 10}};
	set<pair<int, int>> s;
	for (auto e : a)
	{
		s.insert(e);
	}

	auto it = s.begin();
	while (it != s.end())
	{
		cout << (*it).first << " " << (*it).second << endl;
		++ it;
	}
}
int main()
{
	test1();

	return 0;
}

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

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

相关文章

一图展示免费开源的分布式版本控制系统​Git

文章目录 前言一、安装Git二、Git配置三、git命令 前言 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。 一、安装Git Windows操作系统…

端到端拥塞控制的本质

昨天整理了一篇 bbr 的微分方程组建模(参见 bbr 建模)&#xff0c;算是 bbr 算法终极意义上的一个总结&#xff0c;最后也顺带了对 aimd 的描述&#xff0c;算是我最近比较满意的一篇分享了。那么接下来的问题&#xff0c;脱离出具体算法&#xff0c;上升到宏观层面&#xff0c…

【Redis】复制(Replica)

文章目录 一、复制是什么&#xff1f;二、 基本命令三、 配置&#xff08;分为配置文件和命令配置&#xff09;3.1 配置文件3.2 命令配置3.3 嵌套连接3.4 关闭从属关系 四、 复制原理五、 缺点 以下是本篇文章正文内容 一、复制是什么&#xff1f; 主从复制 master&#xff…

【UE5.1 角色练习】15-枪械射击——子弹发射物

目录 效果 步骤 一、创建并发射子弹 二、优化子弹 效果 步骤 一、创建并发射子弹 1. 在前面的文章中&#xff08;【UE5.1 角色练习】06-角色发射火球-part1&#xff09;我们创建了蓝图“BP_Skill_FireBall” 这里我们复制一份命名为“BP_Ammo_5mm”&#xff0c;用于表示…

OpenAI终止对中国提供API服务,对国内AI市场产生重大冲击?

6月25日&#xff0c;OpenAI突然宣布终止向包括中国在内的国家地区提供API服务&#xff0c;本月9日这一政策已经正式生效了&#xff01; 有人说&#xff0c;这个事件给中国AI行业带来很大冲击&#xff01;是这样吗&#xff1f;在展开讨论前&#xff0c;我们先来看看什么是API服务…

详解如何通过稀疏向量优化信息检索

在信息检索方法的发展历程中&#xff0c;我们见证了从传统的统计关键词匹配到如 BERT 这样的深度学习模型的转变。虽然传统方法提供了坚实的基础&#xff0c;但往往难以精准捕捉文本的语义关系。如 BERT 这样的稠密检索方法通过利用高维向量捕获文本的上下文语义&#xff0c;为…

配置Maven并使用IDEA新建一个简单的Springboot项目

一.maven的配置 1.查看电脑上是否配置了maven ①使用快捷键“WinR”打开运行窗口&#xff0c;在窗口中输入cmd&#xff0c;点击确定进入黑色命令窗口 ②在命令行窗口中输入如下命令 mvn -version 如果出现下面的提示则表示该电脑已配置maven&#xff0c;否则需要进行maven配…

pdf工具

iLovePDF | 为PDF爱好者提供的PDF文件在线处理工具 https://www.ilovepdf.com/zh-cn 图片 pdf 合并成一个pdf也可以拆分

基于AT89C51单片机超声波水位液位控制系统设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的1616点阵LED显示器字符滚动显示设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 设计任务与要求 原理图 仿真图 代码 系统论文 资源下载 设计任务与要求…

css横向滚动条支持鼠标滚轮

在做视频会议的时候&#xff0c;标准模式视图会有顶部收缩的一种交互方式&#xff0c;用到了横向滚动&#xff1b;一般情况下鼠标滚轮只支持竖向滚动&#xff0c;这次写个demo是适配横向滚动&#xff1b; 效果图展示 实现横向滚动条顶部显示 <div className{style.remote_u…

【C++基础】初识C++(2)--引用、const、inline、nullptr

目录 一、引用 1.1 引用的概念和定义 1.2 引用的特性 1.3引用的使用 1.4 const引用 1.5 指针和引用的关系 二、inline 三、nullptr 一、引用 1.1 引用的概念和定义 引⽤不是新定义⼀个变量&#xff0c;⽽是给已存在变量取了⼀个别名&#xff0c;编译器不会为引⽤…

打造你的智能家居指挥中心:基于STM32的多协议(zigbee、http)网关(附代码示例)

1. 项目概述 随着物联网技术的蓬勃发展&#xff0c;智能家居正逐步融入人们的日常生活。然而&#xff0c;市面上琳琅满目的智能家居设备通常采用不同的通信协议&#xff0c;导致不同品牌设备之间难以实现互联互通。为了解决这一难题&#xff0c;本文设计了一种基于STM32的多协…

IOT物联可编程中控主机同时具备中控主机和交换机的功能

可编程中控主机同时具备中控主机和交换机的功能 GF-MAXCCP可编程中控主机确实同时具备中控主机和交换机的功能&#xff0c;这种设备在现代化会议室、音视频系统及其他集中控制场景中发挥着重要作用。以下是关于GF-MAXCCP可编程中控主机具备中控主机和交换机功能的详细解释&…

ubuntu基于cmakelist的Qt工程,如何将图片打包进二进制程序

qt界面使用的图片打包进入二进制可执行程序&#xff0c;可以避免发布的软件&#xff0c;因为路径问题无法加载图片的问题。 以下步骤参考自百度AI. 步骤如下&#xff1a; 1.创建一个新的Qt资源文件&#xff08;.qrc文件&#xff09; 2.在*.qrc文件中添加图片路径 qrc文件使用…

在Vue中,子组件向父组件传递数据

在Vue中&#xff0c;子组件向父组件传递数据通常通过两种方式实现&#xff1a;事件和回调函数。这两种方式允许子组件与其父组件进行通信&#xff0c;传递数据或触发特定的行为。 1. 通过事件传递数据 子组件可以通过触发自定义事件&#xff0c;并将数据作为事件的参数来向父组…

win11显示泛白关闭HDR

由于自己拿键盘胡乱玩了一会&#xff0c;然后发现显示泛白&#xff0c;很奇怪&#xff0c;用笔记本试了&#xff0c;不是显示器的问题&#xff0c;在网上找不到相关问题的回复&#xff0c;找显卡客服怎么都不好使&#xff0c;卸载显卡驱动可行&#xff0c;但是装上又有问题了。…

案例 | 人大金仓助力山西政务服务核心业务系统实现全栈国产化升级改造

近日&#xff0c;人大金仓支撑山西涉企政策服务平台、政务服务热线联动平台、政务网、办件中心等近30个政务核心系统完成全栈国产化升级改造&#xff0c;推进全省通办、跨省通办、综合业务受理、智能审批、一件事一次办等业务的数字化办结进程&#xff0c;为我国数字政务服务提…

云盘挂载 开机自动模拟 cmd- alist server

云盘挂载 开机自动模拟 cmd- alist server 打开Kimi智能助手, 网址:Kimi.ai - 帮你看更大的世界 (moonshot.cn) 问他: 帮我写一个vbs命令:在D:\sky目录下, 然后cmd, 进入命令行后, 输入 alist server 然后回车 这里 这个目录, 换成自己的 alist.exe所在目录 下面是我完善的示…

对照ui图进行大屏幕适配,echerts适配

1.先找到ui图&#xff0c;我这边是1920*1080的屏幕进行的设计 2.在界面找到跟样式的字体大小&#xff0c;进行设置&#xff0c;一般ui设置字体大小便可 3.在js中写入原生js代码 function adapter() {//获取布局视口宽度&#xff0c;布局视口设备横向独立像素值const dpWidth…

锂电池剩余寿命预测 | Matlab基于Transformer的锂电池剩余寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于Transformer的锂电池剩余寿命预测 Matlab基于Transformer的锂电池剩余寿命预测&#xff08;单变量&#xff09; 运行环境Matlab2023b及以上 NASA数据集&#xff0c;B0005号电池数据训练&#xff0c;B00…