C++ unordered封装

C++ 哈希-CSDN博客

哈希表是unordered系列容器的底层逻辑,再实现了哈希的底层后,我们按照如下步骤封装unordered:

1. 改变数据类型,将HashTable中的所有的_kv都改成T

2. 因为map需要取key,写一个KeyOfT的仿函数并封装

3. iterator , ConstIterator的实现和封装

4. 解决set和map中的key不能修改(value应该设计成可以修改)

5. opereator[]

依照上述思路,我们来实现代码。 

1. 调整数据类型

                                   

但是在改数据的过程中,会发现一些需要KeyOfT的内容(不明白什么是KeyOfT的可以先去看红黑树改造为set和map)

因为不确定data是单个数据或者是一个pair,不能直接这样用first。

2. KeyOfT

然后分别拿两个仿函数KeyOfMap和KeyOfSet: 

            

对照着到HashTable中也去改变一下: 

定义出仿函数对象 :

         

然后要将刚刚写的"data.first"都改了:

有细心的读者可能会问,为什么HashTable需要既传Key,又传T,原因是Key是需要被当做一个类型去使用的,比如Find函数。


3. 迭代器

               

关于迭代器的遍历:

        一个桶内很好动,一直it = it->_next即可;可是一个桶走完了如何找下一个桶?

因为每一条链都是独立的,因此迭代器中光有一个节点指针是不够的。

                  

库中的实现方式:

                        

直接传过来整个表对象,这样就能用_hst里的_table来遍历了。   

因此,构造HSTIterator时需要多一个参数

 


 利用哈希映射找到下一个该去的位置:

                                                     

解决思路:通过_pnode重新找一个当前的hashi并遍历                                                   

这样就能根据迭代器指向的元素的data计算出一个hashi,但是需要先把将key转换成int的仿函数Hashfunc传入。

Self& operator++()
{
	if (_pnode->_next) {
		_pnode = _pnode->_next;
	}
	else {
		//去找下一条链
		KeyOfT kot;
		Hash _hs;
		size_t hashi = _hs(kot(_pnode->_data)) % _hst->_table.size();
		//找到了_pnode指向数据所对应的hashi,现在让hashi在vector<Node*>中往后找到有效位置
		while (hashi < _hst->_table.size())
		{
			++hashi;
			if (_hst->_table[hashi] != nullptr) {
				_pnode = _hst->_table[hashi];
				break;
			}
		}
		//走到这的时候,可能是hashi已经走到了末尾,也可能是找到了有效位置所以break了
		if (hashi == _hst->_table.size()) {
			_pnode = nullptr;
		}
	}
	return *this;
}

hashi和表中的vector的size一样大的时候,表明已经走完了vector但是没有遇到合适的桶。

再实现几个小接口:


 然后就可以回到HashTable中去封装iterator了:

                                  (为了让编译器检查通过,还要在最后加一个return)

 End直接返回一个Iterator(nullptr,this)即可。

回到两个unordered中,封装迭代器:

模版类中拿内置类型,需要加一个typename说明是类型而不是static修饰的变量。 


我们尝试对已经写好的代码进行纠错和更正,现在还有以下几个问题值得说明:

 iterator中使用了HashTable,HashTable中的Begin()等函数使用了iterator。两个模块在互相使用、互相包,所以编译iterator的时候找不到hashtable

 解决办法:前置声明。

在写iterato之前先声明HashTable。


友元:

现在存在的问题:

在迭代器(HSTIterator)的operator++中,我们访问了_table,但是_table是私有,是不能被访问的

_table是私有,但是我们要在iterator中访问他,因此需要友元。

普通类的友元直接frend即可,但是类模版的友元:

要在friend的声明前加上模版参数。

最后再封装constIterator

ConstIterator在构造时会有问题

错误出现在HashTable封装的这一层上:

这里的this是被const修饰了的,所以传进去构造ConstIterator的this也是被const修饰了的。

而红框中的pht是没有const修饰的,所以出现了权限的错误。

但是请注意:对于构造函数和析构函数的this添加const修饰是非法的,所以只修饰hst即可。 

正确修改:


3. key不能修改

因为map和set都是不允许改变T(也就是value)的数值的,所以第二个K要改成const。 

set:

map:

其他小接口直接套:

                               


4.operator方括号

根据库中的逻辑改写insert,然后再利用Insert实现方括号访问。

pair<Iterator,bool> insert(const T& data) {
	HashFunc<K> hs;
	KeyOfT kot;
	if (Find(kot(data))!=End()) return make_pair(Find(kot(data)),false);//!!!!!data.first应该改成KeyOfT来控制

	//扩容
	if ((double)_n / _tables.size() >= 1) {
		/*HashTable newHT;
		newHT._tables.resize(2 * _tables.size());

		for (int i = 0; i < _tables.size(); i++) {
			Node* cur = _tables[i];
			while (cur) {
				newHT.insert(cur->_kv);
				cur = cur->_next;
			}
		}
		_tables.swap(newHT._tables);*/

		vector<Node*> newTable;
		newTable.resize(_tables.size() * 2);
		for (int i = 0; i < _tables.size(); i++) {
			Node* cur = _tables[i];
			while (cur) {
				Node* next = cur->_next;
				//找新表的下标
				size_t hashi = hs(kot(cur->_data)) % newTable.size();//!!!!!data.first应该改成KeyOfT来控制
				//头插到新表
				cur->_next = newTable[hashi];
				newTable[hashi] = cur;

				cur = next;
			}
			_tables[i] = nullptr;
		}
		_tables.swap(newTable);
	}


	//头插
	Node* newnode = new Node(data);
	size_t hashi = hs(kot(data)) % _tables.size();
	if (_tables[hashi] == nullptr) {
		_tables[hashi] = newnode;
	}
	else {
		Node* cur = newnode;
		cur->_next = _tables[hashi];
		_tables[hashi] = cur;
	}
	++_n;
	return make_pair(Iterator(newnode,this), true);
}

 利用insert :


5. 控制HashFunc

 如果此时传入一个Date的自定义类型进入unordered_set,会因无法对“日期类”取模而报错。

原因是class Hash这个默认参数传参的位置不对。像日期类这样一个特殊的类,他的哈希映射函数和我们之前所实现的都不一样,需要将日期类传入set或map的用户自己来传入哈希映射。

所以,应该将这个控制提到外层,并且加入默认参数。

     

比如现在要传Date类型的,就需要自己传一个Hash的函数上去。(Hash是用来将key转化为int以便进行取模的函数)

注意,改变一个位置的模版参数,所有其他对应位置的模版参数都需要改变! 


6. 小结

回过头看:

现在,unordered系列容器中很多我们之前不理解的接口就能理解了。

比如bucket_count就是返回桶的数量(包括空桶和非空桶)。

                                       

 在对实现出来的数据结构进行测试时也发现,扩容对于unordered系列容器都是不小的消耗,所以提前reserve的意义就体现出来了,的确能加快速度。


完整代码链接:

111 · 2096177 · lsnmjp/c语言学习过程 - Gitee.com 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Nginx】前端项目开启 Gzip 压缩大幅提高页面加载速度

背景 Gzip 是一种文件压缩算法&#xff0c;减少文件大小&#xff0c;节省带宽从而提减少网络传输时间&#xff0c;网站会更快更丝滑。 // nginx roothcss-ecs-1d22:/etc/nginx# nginx -v nginx version: nginx/1.24.0// node ndde v18.20.1// dependencies "vue": …

在线教育辅助:SpringBoot试题库系统精讲

2 相关技术 2.1 Spring Boot框架简介 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Sprin…

【前端基础】CSS基础

目标&#xff1a;掌握 CSS 属性基本写法&#xff0c;能够使用文字相关属性美化文章页。 01-CSS初体验 层叠样式表 (Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;&#xff0c;是一种 样式表 语言&#xff0c;用来描述 HTML 文档的呈现&#xff08;美化内容&#…

操作系统进程的描述与控制知识点

前趋图和程序执行 前趋图 定义&#xff1a; 前趋图是指一个有向无循环图&#xff0c;可记为 DAG&#xff0c;它用于描述进程之间执行的先后顺序图形表示&#xff1a; 程序的执行 程序顺序执行时&#xff0c;系统资源的利用率很低 程序顺序执行时的特征 顺序性封闭性可再现性 …

【观成科技】APT组织常用开源和商业工具加密流量特征分析

概述 在当前的网络安全环境中&#xff0c;APT组织的活动愈发频繁&#xff0c;利用其高级技术和社会工程手段&#xff0c;针对全球范围内的政府、军事和企业目标发起了一系列复杂的网络攻击。在不断升级的攻击中&#xff0c;开源和商业工具凭借其灵活性、易用性和全球化攻击能力…

自杀一句话木马(访问后自动删除)

在做安全测试时&#xff0c;例如文件上传时就要上传可以解析的脚本文件解析证明存在漏洞&#xff0c;这个时候就需要(访问后自动删除文件的一句话木马) PHP <?php echo md5(1);unlink(__FILE__); ?> 访问后自动删除

在Microsoft Outlook日历中添加多个时区

在Microsoft Outlook日历中添加多个时区 1.单击Outlook中的文件选项卡&#xff0c;单击选项 2.左侧菜单中选择日历 3.向下滚动到时区部分&#xff0c;并标记当前时区&#xff0c;比如China 4.选中“显示第二个时区”框 5.选择第二个时区并给它一个标签&#xff0c;比如Germa…

python常用的第三方库下载方法

方法一&#xff1a;打开pycharm-打开项目-点击左侧图标查看已下载的第三方库-没有下载搜索后点击install即可直接安装--安装成功后会显示在installed列表 方法二&#xff1a;打开dos窗口输入命令“pip install requests“后按回车键&#xff0c;看到successfully既安装成功&…

Rust 力扣 - 238. 除自身以外数组的乘积

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 这题主要有个关键点&#xff0c;就是元素能取0&#xff0c;然后我们分类讨论元素为0的数量 如果数组中存在至少两个元素为0&#xff0c;则每个元素的除自身以外的乘积为0如果数组中仅存在一个0&#xff0c;则为…

二、应用层,《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》

文章目录 零、前言一、应用层协议原理1.1 网络应用的体系结构1.1.1 客户-服务器(C/S)体系结构1.1.2 对等体&#xff08;P2P&#xff09;体系结构1.1.3 C/S 和 P2P体系结构的混合体 1.2 进程通信1.2.1 问题1&#xff1a;对进程进行编址&#xff08;addressing&#xff09;&#…

【计算机网络篇】数据链路层(14)虚拟局域网VLAN(概述,实现机制)

文章目录 &#x1f6f8;虚拟局域网VLAN&#x1f354;虚拟局域网VLAN的实现机制&#x1f95a;IEEE 802.1Q帧&#x1f95a;以太网交换机的接口类型&#x1f5d2;️例一&#xff1a;在一个交换机上不进行人为的VLAN划分&#xff0c;交换机各接口默认属于VLAN1且类型为Access的情况…

【无人机设计与控制】红嘴蓝鹊优化器RBMO求解无人机路径规划MATLAB

摘要 无人机在复杂环境中的路径规划是一个非线性、非凸优化问题&#xff0c;具有高维度和多约束性。本文提出了基于红嘴蓝鹊优化器&#xff08;RBMO&#xff09;的方法&#xff0c;用于求解无人机路径规划问题。RBMO算法借鉴了红嘴蓝鹊的觅食和群体行为&#xff0c;以全局搜索…

跨平台OFD、PDF文档预览UTS插件

〇、介绍 Seal-OfdReader是跨平台OFD文档预览原生插件&#xff0c;具有以下特点&#xff1a; 支持UniApp项目集成&#xff0c;也支持原生Android项目集成 非腾讯X5&#xff0c;无内核加载&#xff0c;高效率、稳定高可用 支持在线文档&#xff0c;也支持离线设备本地文档 支…

电机学习-SPWM原理及其MATLAB模型

SPWM原理及其MATLAB模型 一、SPWM原理二、基于零序分量注入的SPWM三、MATLAB模型 一、SPWM原理 SPWM其实是相电压的控制方式&#xff0c;定义三相正弦相电压的表达式&#xff1a; { V a m V m sin ⁡ ω t V b m V m sin ⁡ ( ω t − 2 3 π ) V c m V m sin ⁡ ( ω t 2…

CasaOS香橙派安装HomeAssistant智能家居系统并实现远程管理家中智能设备

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

哈希表,哈希桶及配套习题

我们今天带大家简单了解哈希表是怎样的&#xff0c;和简单模拟哈希桶&#xff0c;还有几道练习题 一&#xff0c;哈希表 什么是哈希表&#xff0c;哈希表是一种非常非常高效的数据结构&#xff0c;它用来搜索我们想要的数据&#xff0c;我们之前学过很多查找方法&#xff0c;最…

R语言贝叶斯分层、层次(Hierarchical Bayesian)模型房价数据空间分析

原文链接&#xff1a;https://tecdat.cn/?p38077 本文主要探讨了贝叶斯分层模型在分析区域数据方面的应用&#xff0c;以房价数据为例&#xff0c;详细阐述了如何帮助客户利用R进行模型拟合、分析及结果解读&#xff0c;展示了该方法在处理空间相关数据时的灵活性和有效性。&a…

拉取git代码不适用ssh,使用用户名及密码

最近换了新电脑&#xff0c;拉取git代码&#xff0c;提示我需要配置ssh&#xff0c;但是着实是有点麻烦了&#xff0c;所以使用用户名和密码的方式可以直接拉取 首先登陆git后找到对应项目地址&#xff0c;有ssh 和http。但是这两种都不是我们要用的地址&#xff0c;使用用户名…

第三十一章 Vue之路由(VueRouter)

目录 一、引言 1.1. 路由介绍 二、VueRouter 三、VueRouter的使用 3.1. 使用步骤&#xff08;52&#xff09; 3.2. 完整代码 3.2.1. main.js 3.2.2. App.vue 3.2.3. Friend.vue 3.2.4. My.vue 3.2.5. Find.vue 一、引言 1.1. 路由介绍 Vue中路由就是路径和组件的映…

Windows转Mac过渡指南

最近由于工作原因开始使用mac电脑&#xff0c;说实话刚拿到手的时候&#xff0c;window党表示真的用不惯。坚持用一下午之后&#xff0c;发现真的yyds&#xff0c;这篇文章说说mac电脑的基本入门指南。 1. 不会使用mac的触摸板&#xff0c;接上鼠标发现滚轮和windows是反的。 …