map和set的简易封装(纯代码)

news2025/1/12 16:15:41

RBTree.h

#pragma once

#include<iostream>
#include<vector>
using namespace std;

enum colar
{   
	red,
	black
};

template<class T>//有效参数就一个 
struct RBTreeNode
{
	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _co(red)
	{}

	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	T _data;
	colar _co;

};

template<class T,class ref,class ptr>
struct _Tree_iterator
{
	typedef RBTreeNode<T> Node;
	typedef _Tree_iterator<T,ref,ptr> self;
	Node* _cur;

	_Tree_iterator(Node* tmp)
		:_cur(tmp)
	{}

	self& operator++()
	{
		//将当前节点看作父节点再分析
		if (_cur->_right == nullptr)//向上返回(前提是父的左孩子)如果是右孩子则表明父亲已经遍历过了
		{
			Node* parent = _cur->_parent;
			while (parent && parent->_right == _cur)//parent可能为空
			{
				_cur = parent;
				parent = _cur->_parent;
			}
			//指向parent指向的left等于_cur 或者parent为空(遍历结束)
			_cur = parent;

		}
		else//自己就属于父节点,找右子树的最左节点
		{
			Node* tmp = _cur->_right;
			while (tmp->_left)//tmp不可能为空
			{
				tmp = tmp->_left;
			}
			_cur = tmp;
		}
		return *this;
	}
	self& operator--()//相较于operator++而言就是 右子树 根 左子树 的遍历方式
	{
		if (_cur->_left == nullptr)//表明当前节点遍历完成,向上返回……
		{
			Node* parent = _cur->_parent;
			while (parent&&parent->_left == _cur)
			{
				_cur = parent;
				parent = parent->_parent;
			}
			_cur = parent;
		}
		else
		{
			//找左子树的最右节点
			_cur = _cur->_left;
			while (_cur->_right)
			{
				_cur = _cur->_right;
			}
		}
		return *this;
	}

	ref operator*()
	{
		return _cur->_data;
	}

	ptr operator->()
	{
		return &_cur->_data;
	}

	bool operator!=(const self& tmp)
	{
		return _cur != tmp._cur;
	}
};

template<class K, class T,class Com_T>
class RBTree
{
	typedef RBTreeNode<T> Node;
	
public:
	typedef _Tree_iterator<T,T&,T*> iterator;
	typedef _Tree_iterator<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 cbegin()const
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return const_iterator(cur);
	}
	const_iterator cend()const 
	{
		return const_iterator(nullptr);
	}

	//pair <iterator, bool> insert(const T& data)//data类型取决于T,而T又取决于map和set
	pair <Node*, bool> insert(const T& data)//data类型取决于T,而T又取决于map和set
	{
		Node* newroot = new Node(data);//默认为红
		if (_root == nullptr)
		{
			_root = newroot;
			_root->_co = black;//设为黑
			return make_pair(newroot,true);
		}
		Node* parent = _root, * cur = _root;
		//插入数据
		Com_T com;
		while (1)
		{
			parent = cur;
			if (com(cur->_data) > com(data))//这里data的类型可能是pair(不确定)
			{
				cur = cur->_left;
				if (cur == nullptr)
				{
					parent->_left = newroot;
					newroot->_parent = parent;
					break;
				}
			}
			else if (com(cur->_data) < com(data))
			{
				cur = cur->_right;
				if (cur == nullptr)
				{
					parent->_right = newroot;
					newroot->_parent = parent;
					break;
				}
			}
			else
			{
				return make_pair(cur, false);//数据相同返回相同数据的迭代器(类似是查找数据)
			}

		}

		//父节点的判断
		cur = newroot;//当前节点就是新插入的节点

		while (parent && parent->_co == red)//父亲节点可能不存在
		{
			Node* pparent = parent->_parent;//parent为红,不可能是根,一定存在pparent
			Node* uncle = nullptr;
			//找叔叔节点
			if (pparent->_right == parent)
				uncle = parent->_parent->_left;
			else
				uncle = parent->_parent->_right;

			if (uncle && uncle->_co == red)//叔叔存在且为红
			{
				//变色
				parent->_co = uncle->_co = black;
				pparent->_co = red;//祖父节点有可能是根节点
				//继续向上更新处理
				cur = pparent;
				parent = cur->_parent;
			}
			else//叔叔节点为空或为黑
			{
				//旋转
				if (pparent->_left == parent && parent->_left == cur)
				{
					//右单旋
					RotateR(pparent);
					parent->_co = black;
					pparent->_co = red;
				}
				else if (pparent->_right == parent && parent->_right == cur)
				{
					//左单旋
					RotateL(pparent);
					parent->_co = black;
					pparent->_co = red;
				}
				else if (pparent->_right == parent && parent->_left == cur)
				{
					//右左双旋
					RotateR(parent);
					RotateL(pparent);
					cur->_co = black;
					pparent->_co = red;
				}
				else if (pparent->_left == parent && parent->_right == cur)
				{
					//左右双旋
					RotateL(parent);
					RotateR(pparent);
					cur->_co = black;
					pparent->_co = red;
				}
				break;//旋转之后新的根节点都是黑色
			}

		}

		_root->_co = black;//循环体内很有可能将根节点改为红
		return make_pair(newroot, true);

	}


	void RotateL(Node* parent)//左单旋
	{
		Node* cur = parent->_right;
		Node* curl = cur->_left;
		Node* pparent = parent->_parent;//提前记录

		parent->_right = curl;
		if (curl)
		{
			curl->_parent = parent;
		}
		cur->_left = parent;
		parent->_parent = cur;

		//处理pparent与parent的连接
		if (_root == parent)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (pparent->_left == parent)
				pparent->_left = cur;
			else
				pparent->_right = cur;
			cur->_parent = pparent;
		}

	}
	void RotateR(Node* parent)//右单旋
	{
		{
			Node* cur = parent->_left;
			Node* curr = cur->_right;
			Node* pparent = parent->_parent;//提前记录

			parent->_left = curr;
			if (curr)
			{
				curr->_parent = parent;
			}
			cur->_right = parent;
			parent->_parent = cur;

			//处理pparent与parent的连接
			if (_root == parent)
			{
				_root = cur;
				cur->_parent = nullptr;
			}
			else
			{
				if (pparent->_left == parent)
					pparent->_left = cur;
				else
					pparent->_right = cur;
				cur->_parent = pparent;
			}

		}
	}

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}

	// 根节点->当前节点这条路径的黑色节点的数量
	bool Check(Node* cur, int blacknum, int ref_val)
	{
		if (cur == nullptr)
		{
			if (blacknum == ref_val)
				return true;
			cout << "每条路径的黑色节点个数不同" << endl;
			return false;
		}
		Node* parent = cur->_parent;
		if (cur->_co == red && parent->_co == red)//向上判断,向下判断的节点可能为空或其它的。
			return false;
		if (cur->_co == black)
			blacknum++;

		return Check(cur->_left, blacknum, ref_val) && Check(cur->_right, blacknum, ref_val);
	}
	bool Is_balance()
	{
		if (_root->_co == red)
			return false;
		if (_root == nullptr)
			return true;

		//不能出现连续红节点
		//每条路径黑色节点要保证相同
		int blacknum = 0;//必须传值,相当于是每个节点都有一个变量表示从根到当前的黑节点个数
		int ref_val = 0;//参考值,求出任意一条路径中黑色节点数目
		Node* cur = _root;
		while (cur)
		{
			if (cur->_co == black)
				ref_val++;
			cur = cur->_left;
		}
		return Check(_root, blacknum, ref_val);
	}

private:
	Node* _root=nullptr;
};

Set.h

#include"RBTree.h"

template<class  key>
class set
{
public:
	struct setCom//仿函数
	{
		const key& operator()(const key& k)
		{
			return k;
		}
	};

	//typedef _Tree_iterator<key> iterator;
	typedef typename RBTree<key, key, setCom>::const_iterator iterator;
	typedef typename RBTree<key, key, setCom>::const_iterator const_iterator;
	//对类模版取内嵌类型,加typename是为了告诉编译器这里是类型

	pair<iterator,bool> insert(const key& k)//此时pair的第一个参数类型是const_iterator
	{
		return _s.insert(k);//insert返回pair<Node*,bool>会构造出pair<iterator,bool>
	}

	iterator begin()const
	{
		return _s.cbegin();
	}
	iterator end()const
	{
		return _s.cend();
	}
	

private:
	RBTree<key, key, setCom> _s;//封装红黑树
};

Map.h

#include"RBTree.h"

template<class  key,class val>
class map
{
public:

	struct mapCom//仿函数
	{
		const key& operator()(const pair<key,val>& p)
		{
			return p.first;
		}
	}; 

	//typedef _Tree_iterator<pair<key,val>> iterator;
	typedef typename RBTree<key, pair<const key, val>, mapCom>::iterator iterator;
	typedef typename RBTree<key, pair<const key, val>, mapCom>::const_iterator const_iterator;
	//对类模版取内嵌类型,加typename是为了告诉编译器这里是类型

	pair<iterator, bool> insert(const pair<key, val>& kv)
	{
		return _m.insert(kv);
	}
	
	iterator begin()
	{
		return _m.begin();
	}
	iterator end()
	{
		return _m.end();
	}
	const_iterator cbegin()const
	{
		return _m.cbegin();
	}
	const_iterator cend()const
	{
		return _m.cend();
	}

	val& operator[](const key& k)
	{
		pair<key, val> tmp(k, val());//val给缺省值,tmp是创建变量
		pair<iterator,bool> ret = insert(tmp);//返回插入的节点的pair

		return (ret.first)->second;
	}

private: 
	RBTree<key, pair<const key, val>,mapCom> _m;//封装红黑树(参数类型决定着红黑树的数据类型)
};  

test.cpp(测试)

#include"Map.h"
#include"Set.h"
#include<string>

void test_set()
{
	set<int> s;
	s.insert(4);
	s.insert(1);
	s.insert(2);
	s.insert(3);
	s.insert(2);
	s.insert(0);
	s.insert(10);
	s.insert(5);

	set<int>::iterator it = s.begin();//浅拷贝
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test_map()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("sort", "xx"));
	dict.insert(make_pair("left", "左边"));
	dict.insert(make_pair("right", "右边"));

	map<string, string>::const_iterator it = dict.cbegin();
	while (it != dict.cend())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

	string arr[] = { "㽶", "香蕉","ƻ", "香蕉", "ƻ", "香蕉", "ƻ", "ƻ", "香蕉", "ƻ", "㽶", "ƻ", "㽶" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		countMap[e]++;
	}

	for (auto kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;
}

int main()
{
	//test_set();
	test_map();

	return 0;
}

如有问题欢迎留言!!!

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

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

相关文章

这么好看的马面裙 ,女儿穿上不要太美了

红色小翻领&#xff0c;上身米白色金貂绒面料精细顺滑非常有质感 另外还有全手工定制的盘口裙子用的是仿宋代宋锦的织金面料 制作工艺非常复杂很重工的一件衣服 出门保证会被夸&#xff01;&#xff01;

用Python制作截图小工具

Python编程语言允许我们执行各种任务&#xff0c;所有这些都是在简单模块和短小精悍的代码的帮助下完成的。在Python的帮助下进行屏幕截图就是这样一项任务。 Python为我们提供了许多模块&#xff0c;使我们能够执行不同的任务。有多种方法可以使用Python及其库进行屏幕截图。…

开源电子画册源码系统 可重复利用 适合任何行业 带完整的搭建教程

电子画册&#xff0c;又称电子样本、电子商刊、电子杂志&#xff0c;是一种集合图片处理、文案策划、音乐加工、视频、统计调查、虚拟现实、三维动画等多种技术和表现形式为一体的多媒体画册&#xff0c;电子杂志是纸质印刷画册&#xff08;样本&#xff09;的升级版本&#xf…

创作者等级终于升到4级了

写了两个月的文章&#xff0c;终于等到4级了。发文纪念一下&#xff1a;

划片机:半导体工艺精细化高效化的新里程碑

随着科技的飞速发展&#xff0c;半导体已经成为现代电子设备的基石&#xff0c;而半导体晶圆的划片机作为半导体制造的核心设备之一&#xff0c;其发展程度直接关系到半导体的质量和产量。近年来&#xff0c;博捷芯精密划片机以其在半导体划片机领域的卓越表现&#xff0c;引领…

mybatis、mysql 创建时间(create_time)异常自动更新为当前时间

目录标题 一、问题二、原因三、解决 一、问题 bug: mybatis更新代码没有修改时间&#xff0c;但是时间会自动更新为当前时间。 。。。 被坑了挺久 二、原因 可能是创建表的时候&#xff0c; Navicat Premium 等可视化工具给你整活了。。。 三、解决 取消勾选。 注意&…

R语言基础入门(学习笔记通俗易懂版)

文章目录 R语言预备知识获取工作目录设置工作目录注释变量名的命名赋值变量的显示查看与清除变量函数帮助文档查询函数安装R包文件的读取文件的输出软件的退出与保存 R语言语法向量向量的创建向量的索引&#xff08;向量元素的提取、删除、添加&#xff09;向量长度的获取向量的…

利用 Kubernetes 降本增效?EasyMR 基于 Kubernetes 部署的探索实践

Kubernetes 是用于编排容器化应用程序的云原生系统。最初由 Google 创建&#xff0c;如今由 Cloud Native Computing Foundation&#xff08;CNCF&#xff09;维护更新。 Kubernetes 是市面上最受欢迎的集群管理解决方案之一。它自动化容器化应用程序的部署、扩展和管理&#…

企业图纸混乱怎么办?

企业图纸混乱怎么办&#xff1f; 随着企业办公自动化的迅速发展&#xff0c;各种技术资料和电子文件日益庞大&#xff0c;图文档管理工作出现新的变化和考验。 在传统的管理模式下&#xff0c;企业的图纸文档分散在各个部门的个人电脑上&#xff0c;致使企业在进行图文档管理的…

统信UOS_麒麟KYLINOS禁用USB存储

原文链接&#xff1a;统信UOS/麒麟KYLINOS禁用USB存储 hello&#xff0c;大家好啊&#xff0c;今天给大家带来一篇在统信UOS/麒麟KYLINOS禁用USB存储的文章&#xff0c;文章通过三种方式&#xff1a;1、在文件管理器中通过图形化方式移除USB&#xff1b;2、通过禁用USB存储模块…

龙迅LT8912B 单通道MIPIDSI桥接LVDS+HDMI(1.4)同显点屏LVDS,加环出一路HDMI

龙迅LT8912B 描述: Lontium LT8912B MIPIDSI到LVDS和HDMI桥采用单通道MIPID-PHY接收器前端配置&#xff0c;每个通道有4个数据通道&#xff0c;每个数据通道运行1.5Gbps&#xff0c;最大输入带宽可达6Gbps。对于屏幕应用&#xff0c;该桥解码MIPIDSI 18bpp RGB666和24bpp RGB…

500mA 线性锂电充电芯片 DP4054/DP4054H完全兼容替代TP4054

锂电池是一种新型的可充电电池&#xff0c;其具有体积小、重量轻、容量大耐用性强等特点&#xff0c;因此被广泛应用于手机、笔记本电脑、移动电源等电了设备上。 充电原理是指电池在充电过程中&#xff0c;用电流将锂离子从外部电源输入电池&#xff0c;使其形成 一个电荷差&…

这几个站点,有点优秀

中国大学慕课网 网址&#xff1a;https://www.icourse163.org/ 大学生们这个白嫖网站咱一定不能错过&#xff0c;与全国801所高效合作&#xff0c;里面都是不同专业的精品课程&#xff0c;关键是它们都是免费的&#xff01;报名学习&#xff0c;就等着知识装满脑袋吧&#xff0…

IO接口基础知识

一、基本概念 IO接口&#xff1a;CPU与IO设备之间的桥梁 1.IO接口分类 专业接口&#xff1a;连接专用设备&#xff0c;常用附加卡的形式来实现通用接口&#xff1a;基本的输入输出接口&#xff0c;如并行口&#xff0c;串行口(外设和接口一侧) 2.IO接口组成 为了实现下图功…

泛型编程 -- 模板详解

一、模板 在没有模板之前&#xff0c;如果我们写一个swap()两数交换函数&#xff0c;因为我们要支持 int 与int 交换 、double 与 double 交换等等情况&#xff0c;所以要实现swap()函数的多个重载&#xff0c;显得很繁琐&#xff0c;于是就引入了模板。 模板就是在需要模板的地…

CTF-栈溢出-基本ROP-【ret2shellcode】

文章目录 ret2shellcodeHTBCyberSanta 2021 sleigh思路exp ret2shellcode 控制程序去执行我们自己填充的代码。 条件&#xff1a; 我们填充的代码的位置具有可执行权限 HTBCyberSanta 2021 sleigh 检查保护 Has RWX segments提示有可读可写可执行的段 main函数 banner函数…

期望、方差

一、期望和方差的定义 随机变量(Random Variable) X 是一个映射&#xff0c;把随机试验的结果与实数建立起了一一对应的关系。而期望与方差是随机变量的两个重要的数字特征。 1. 期望(Expectation, or expected value) 期望是度量一个随机变量取值的集中位置或平均水平的最基…

Java简介、基本语法

一、Java简介&#xff1a; Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。 Java主要的特性&#xff1a; 1、Java语言是简单的的&#xff1a; Java语言的语法与C、C语言接近。Java丢弃了C中的一些特性&#xff0c;如操…

系列三、GC垃圾回收【总体概览】

一、GC垃圾回收【总体概览】 JVM进行GC时&#xff0c;并非每次都对上面的三个内存区域&#xff08;新生区、养老区、元空间/永久代&#xff09;一起回收&#xff0c;大部分回收的是新生区里边的垃圾&#xff0c;因此GC按照回收的区域又分为了两种类型&#xff0c;一种是发生在新…

redis高级案列case

案列一 双写一致性 案例二 双锁策略 package com.redis.redis01.service;import com.redis.redis01.bean.RedisBs; import com.redis.redis01.mapper.RedisBsMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; imp…