【C++】哈希对unordered_map和unodered_set的封装

在这里插入图片描述

🚀write in front🚀
📜所属专栏: C++学习
🛰️博客主页:睿睿的博客主页
🛰️代码仓库:🎉VS2022_C语言仓库
🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!
关注我,关注我,关注我你们将会看到更多的优质内容!!

在这里插入图片描述

文章目录

  • 前言
  • 一.哈希表的修改
  • 二.封装map和set
  • 三.普通迭代器
  • 四.const迭代器
  • 五.insert返回值,operator[]和key不能修改的问题
  • 总结

前言

  在前面的学习里面,我们完成了红黑树对map和set的封装,今天我们就用哈希里面的开散列对unordered_map和unodered_set进行封装。其实哈希的封装和红黑树的封装是非常相像的,所以我们这里简单道来。

一.哈希表的修改

  和红黑树一样,我们把模板参数改成:

template<class K,class T,class KeyOfT,class HashFunc = DefaultHashFunc<K>>
class HashTable
{}

K:关键码类型
T:对于unordered_map,T就是有个键值对;对于unordered_set,T就是Key。
keyOfT:取出元素(主要是为unordered_map设计)
HashFunc:仿函数,将key转换成整数,才能进行取模。
结点改为:

template<class T>struct HashNode{T _data;HashNode<T>* _next=nullptr;HashNode(const T& data):_data(data){}};

二.封装map和set

对于map和set,我们也是直接修改一下模板传过来的值就可以了。

三.普通迭代器

template<class K, class T,class Ptr,class Ref, class KeyOfT, class  HashFunc>struct HTIterator{public:typedef HashNode<T> Node;typedef HTIterator<K, T,Ptr,Ref, KeyOfT, HashFunc> Self;typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;Node* _node;HashTable <K, T, KeyOfT, HashFunc>* _pht;HTIterator(Node* node, HashTable <K,T,KeyOfT, HashFunc>* pht) :_node(node),_pht(pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}bool operator!=(const Self& t){return _node != t._node;}};

在这里对于迭代器的++操作,要寻找下一个元素就有两种情况,链表的下一个或者下一个哈希桶,所以这里为了找到下一个哈希桶,就要把哈希传过来,所以这里要传哈希的指针,为了使迭代器可以写出哈希的指针,这里的迭代器的模板参数也要有keyofThashfunc

	Self& operator++(){if (_node->_next){_node = _node->_next;}else{KeyOfT kot;HashFunc hf;size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();hashi++;while (hashi < _pht->_table.size()){if (_pht->_table[hashi]){_node = _pht->_table[hashi];return *this;}hashi++;}_node = nullptr;}return *this;}

四.const迭代器

  随后我们就可以构造出const迭代器了。随后我们就要写出用普通迭代器构造const迭代器的构造函数。并且这里要在hashtable之前使用hashtable,就要先申明一下:

//这里就别写= DefaultHashFunc<K> 了,不然会保错:重定义参数template<class K, class T, class KeyOfT, class  HashFunc>class HashTable;template<class K, class T,class Ptr,class Ref, class KeyOfT, class  HashFunc>struct HTIterator{public:typedef HashNode<T> Node;typedef HTIterator<K, T,Ptr,Ref, KeyOfT, HashFunc> Self;typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;Node* _node;//这里如果传过来的是const类型的pht,权限会放大,所以说要改成下面的情况://HashTable <K, T, KeyOfT, HashFunc>* _pht;/*HTIterator(Node* node, HashTable <K,T,KeyOfT, HashFunc>* pht) :_node(node),_pht(pht){}*///因为在这里我们对于这个哈希桶不会进行修改,所以直接用const修饰,这样只会出现权限的缩小或平移const HashTable <K, T, KeyOfT, HashFunc>* _pht;HTIterator(Node* node, const HashTable <K, T, KeyOfT, HashFunc>* pht) :_node(node), _pht(pht){}HTIterator(const iterator& it) :_node(it._node), _pht(it._pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}Self& operator++(){if (_node->_next){_node = _node->_next;}else{KeyOfT kot;HashFunc hf;size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();hashi++;while (hashi < _pht->_table.size()){if (_pht->_table[hashi]){_node = _pht->_table[hashi];return *this;}hashi++;}_node = nullptr;}return *this;}bool operator!=(const Self& t){return _node != t._node;}};

五.insert返回值,operator[]和key不能修改的问题

  这里和红黑树封装map和set类似,就不用多说了。下面看看完整代码:

#pragma once
#include<vector>
#include<iostream>
using namespace std;template<class T>
class DefaultHashFunc
{
public:size_t operator()(const T& key){return (size_t)key;}
};template<>
class DefaultHashFunc<string>
{
public:size_t operator()(const string& key){size_t value = 1;for (auto& e : key){value *= 131;value += e;}return value;}
};
namespace hash_bucket
{template<class T>struct HashNode{T _data;HashNode<T>* _next=nullptr;HashNode(const T& data):_data(data){}};//这里就别写== DefaultHashFunc<K> 了,不然会保错:重定义参数template<class K, class T, class KeyOfT, class  HashFunc >class HashTable;template<class K, class T,class Ptr,class Ref, class KeyOfT, class  HashFunc>struct HTIterator{public:typedef HashNode<T> Node;typedef HTIterator<K, T,Ptr,Ref, KeyOfT, HashFunc> Self;typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;Node* _node;//这里如果传过来的是const类型的pht,权限会放大,所以说要改成下面的情况://HashTable <K, T, KeyOfT, HashFunc>* _pht;/*HTIterator(Node* node, HashTable <K,T,KeyOfT, HashFunc>* pht) :_node(node),_pht(pht){}*///因为在这里我们对于这个哈希桶不会进行修改,所以直接用const修饰,这样只会出现权限的缩小或平移const HashTable <K, T, KeyOfT, HashFunc>* _pht;HTIterator(Node* node, const HashTable <K, T, KeyOfT, HashFunc>* pht) :_node(node), _pht(pht){}HTIterator(const iterator& it) :_node(it._node), _pht(it._pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}Self& operator++(){if (_node->_next){_node = _node->_next;}else{KeyOfT kot;HashFunc hf;size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();hashi++;while (hashi < _pht->_table.size()){if (_pht->_table[hashi]){_node = _pht->_table[hashi];return *this;}hashi++;}_node = nullptr;}return *this;}bool operator!=(const Self& t){return _node != t._node;}};template<class K,class T, class KeyOfT,class HashFunc= DefaultHashFunc<K> >class HashTable{typedef HashNode<T> Node;//友员声明template<class K, class T, class Ptr,class Ref,class KeyOfT, class HashFunc>friend struct HTIterator;public:HashTable(){_table.resize(10,nullptr);}~HashTable(){for (int i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_table[i] = nullptr;}}typedef HTIterator<K, T,T*,T&, KeyOfT, HashFunc>  iterator;typedef HTIterator<K, T, const T*, const T&, KeyOfT, HashFunc>  const_iterator;iterator begin(){for (int i = 0; i < _table.size(); i++){if (_table[i]){return iterator(_table[i], this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}const_iterator begin() const{for (int i = 0; i < _table.size(); i++){if (_table[i]){return const_iterator(_table[i], this);}}return const_iterator(nullptr, this);}const_iterator end() const{return const_iterator(nullptr, this);}pair<iterator,bool> Insert(const T& data){KeyOfT kot;auto it = Find(kot(data));if (it!=end()){return make_pair(it,true);}HashFunc hf;if (_table.size() == _n){//扩容HashTable newhash;size_t newsize = _table.size() * 2;newhash._table.resize(newsize);for (int i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;size_t hashi = hf(kot(cur->_data)) % newsize;cur->_next = newhash._table[i];newhash._table[i] = cur;cur = next;}_table[i] = nullptr;}_table.swap(newhash._table);}size_t hashi = hf(kot(data)) % _table.size();Node* cur = new Node(data);cur->_next = _table[hashi];_table[hashi] = cur;_n++;return make_pair(iterator(cur,this),false);}iterator Find(const K& key){HashFunc hf;KeyOfT kot;size_t hashi = hf(key) % _table.size();Node* cur = _table[hashi];while (cur){if (kot(cur->_data) == key){return iterator(cur,this);}cur = cur->_next;}return end();}bool Erase(const K& key){HashFunc hf;KeyOfT kot;size_t hashi = hf(key) % _table.size();Node* cur = _table[hashi];Node* prev = nullptr;while (cur){if (kot(cur->_data) ==key){if (prev == nullptr){_table[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;cur = nullptr;return true;}prev = cur;cur = cur->_next;}return false;}void Print(){for (int i = 0; i < _table.size(); i++){printf("[%d]: ", i);Node* cur = _table[i];while (cur){cout << "("<<cur->_kv.first << ":" << cur->_kv.second<<")" << " ->";cur = cur->_next;}printf("NULL\n");}}private:vector<Node*>  _table;size_t _n=0;};
}

set的封装:

namespace zxr
{template<class K>class unordered_set{private:struct SetKeyOfT{const K& operator()(const K& key){return key;}};hash_bucket::HashTable<K, K,SetKeyOfT> _ht;public:typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator;iterator begin()const{return _ht.begin();}iterator end()const{return _ht.end();}pair<iterator,bool> insert(const K&data){pair<typename hash_bucket::HashTable<K, K, SetKeyOfT>::iterator, bool> it= _ht.Insert(data);return pair<iterator,bool>(it.first, it.second);}bool erase(const K& key){return _ht.Erase(key);}bool find(const K& key){return _ht.Find(key);}};
}

map的封装:

namespace zxr
{template<class K,class V>class unordered_map{private:struct MapKeyOfT{const K& operator()(const pair<const K,V>& kv){return kv.first;}};hash_bucket::HashTable<K, pair<const K,V>, MapKeyOfT> _ht;public:typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::iterator iterator;typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin()const{return _ht.begin();}const_iterator end()const{return _ht.end();}pair<iterator,bool> insert(const pair<const K,V>& data){return _ht.Insert(data);}V& operator [](const K& key){auto it = insert(make_pair(key,V()));return it.first->second;}bool erase(const K& key){return _ht.Erase(key);}bool find(const K& key){return _ht.Find(key);}};
}

总结

在这里插入图片描述
  在这里我们在讲几个之前没理解的点,我们的迭代器在平时可以用const迭代器来介绍迭代器,就是因为库里面已经写了用普通迭代器构造const迭代器的构造函数,随意我们才能理所当然的使用。
这里要强调的还是,同一模板传了不同参数,此时就生成了两个不同的类型,无论模板参数是const还是普通,都不在是同一个类型了。
在这里插入图片描述

封装的过程都是这样的:
1、哈希表
2、封装map和set
3、普通迭代器
4、const迭代器
5、insert返回值 operator[]
6、key不能修改的问题

  更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

专栏订阅:
每日一题
C语言学习
算法
智力题
初阶数据结构
Linux学习
C++学习
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

在这里插入图片描述

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

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

相关文章

Godot 单元测试

前言 单元测试是我们常用的功能&#xff0c;Godot作为一个游戏&#xff0c;单元测试和热重载是我们常用的功能。这里我们讲解最简单的单元测试的情况。 Godot 配置 我们添加一个最简单的节点&#xff0c;挂载一个最简单的脚本。 添加测试方法&#xff08;只能是静态方法&…

【Python】Python语言基础(中)

第十章 Python的数据类型 基本数据类型 数字 整数 整数就是整数 浮点数 在编程中&#xff0c;小数都称之为浮点数 浮点数的精度问题 print(0.1 0.2) --------------- 0.30000000000000004 ​​1.可以通过round()函数来控制小数点后位数 round(a b)&#xff0c;则表示…

Linux该如何学习,给你支招

如果你已经确定对 Linux 产生了兴趣&#xff0c;那么接下来我们介绍一下学习 Linux 的方法。这只是自己关于学习Linux的建议。 一、如何去学习 学习大多类似庖丁解牛&#xff0c;对事物的认识一般都是由浅入深、由表及里的过程&#xff0c;循序才能渐进。学习 Linux 同样要有一…

关于RNNoise、webrtc_ns、三角带通滤波器、对数能量

语音特征参数MFCC提取过程详解 其中讲解了&#xff1a;三角带通滤波器 、计算每个滤波器组输出的对数能量、对数能量、经离散余弦变换&#xff08;DCT&#xff09;得到MFCC系数 推荐阅读某乎这位大佬的全部文章&#xff1a; 下面是几篇出自这位大佬的很好的文章&#xff1a; …

SSH 基础学习使用

什么是SSH 1.SSH SSH&#xff08;Secure Shell&#xff09; 是较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议&#xff0c;利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。 实际应用中&#xff0c;主要用于保证远程登录和远程通信的安全&#…

微信小程序入门讲解【超详细】

一. 微信小程序简介 1.1 什么是小程序 2017年度百度百科十大热词之一 微信小程序&#xff08;wei xin xiao cheng xu&#xff09;&#xff0c;简称小程序&#xff0c;英文名Mini Program&#xff0c;是一种不需要下载安装即可使用的应用( 张小龙对其的定义是无需安装&#xf…

如何创建自定义前端组件?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

VScode运行C/C++

VScode运行C/C VScode的安装这里不讲 一、mingw64的下载 二、VS code打开文件夹与创建C文件 ----------------这一步给萌新看&#xff0c;有C和VScode的基础可跳过---------------- 1.创建一个文件夹 2.vscode打开刚刚创建的文件夹 3.新建文件&#xff0c;在输入文件名1.c后…

Unity实现摄像机向屏幕中间发射射线射击物体

1.创建一个准星放在屏幕中间 外部找个PNG透明图&#xff0c;拖到Unity文件夹&#xff0c;右上角改成精灵sprite2d 2.添加到UI画布 3.写脚本 首先&#xff0c;我们需要引入一些 "工具"&#xff0c;就像我们在玩游戏时要先下载游戏客户端一样。这里的 "工具&quo…

iOS- flutter flavor 多环境Configurations配置

一、点击PROJECT的Runner&#xff0c;选择Info选项&#xff0c;在Configurations下方的号添加不同环境的配置&#xff0c;如下图&#xff1a; 二、选择TAGETS的Runner项目&#xff0c;选择Build Settings选项&#xff0c;在输入框输入package&#xff0c;为不同环境配置相应的…

UML组件图综合指南:设计清晰、可维护的软件系统

介绍&#xff1a; UML&#xff08;Unified Modeling Language&#xff09;组件图是软件系统设计中的重要工具&#xff0c;用于描绘系统的物理结构和组件之间的关系。在软件工程中&#xff0c;通过创建清晰的组件图&#xff0c;团队能够更好地理解系统的模块化结构和组织关系&a…

二十四、【参考素描三大面和五大调】

文章目录 三种色面(黑白灰)五种色调 这个可以参考素描对物体受光的理解&#xff1a;素描调子的基本规律与素描三大面五大调物体的明暗规律 三种色面(黑白灰) 如下图所示&#xff0c;我们可以看到光源是从亮面所对应的方向射过来的,所以我们去分析图形的时候&#xff0c;首先要…

C# excel操作

使用库 Spire.Xls 下载 示例数据 代码示例 1.删除列 代码 private static void DeleteExcelColumns1(string excelPath) {if (excelPath.Length 0) {Console.WriteLine("excel文件路径为空");}else{Console.WriteLine("删除列方法1&#xff1a;保留第一列&…

好的摄影师都会iPhone 8和iOS 11的这三项功能

众所周知&#xff0c;苹果的手机像素一直处于智能手机摄影的前沿&#xff0c;在即将到来的九月&#xff0c;苹果公司准备证明他拥有最好的相机技术。 虽然我们还不知道iPhone 8摄像头的具体细节&#xff0c;如几百万像素、光学变焦是多少&#xff0c;但我们确实知道苹果正在给i…

Webmin(CVE-2019-15107)远程命令执行漏洞复现

漏洞编号 CVE-2019-15107 webmin介绍 什么是webmin Webmin是目前功能最强大的基于Web的Unix系统管理工具。管理员通过浏览器访问Webmin的各种管理功能并完成相应的管理动作http://www.webmin.com/Webmin 是一个用 Perl 编写的基于浏览器的管理应用程序。是一个基于Web的界面…

Rust入门基础

文章目录 Rust相关介绍为什么要用Rust&#xff1f;Rust的用户和案例 开发环境准备安装Rust更新与卸载Rust开发工具 Hello World程序编写Rust程序编译与运行Rust程序 Cargo工具Cargo创建项目Cargo构建项目Cargo构建并运行项目Cargo检查项目Cargo为发布构建项目 Rust相关介绍 为…

Spring Boot自动加载

问&#xff1a;自动装配如何实现的&#xff1f; 答&#xff1a;简单来说就是自动去把第三方组件的Bean装载到IOC容器中&#xff0c;不需要开发人员再去写Bean相关的配置&#xff0c;在springboot应用里面只需要在启动类上去加上SpringBootApplication注解&#xff0c;就可以去实…

计算机毕业设计选什么题目好?springboot 幼儿园管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

简单使用 Hugo 博客

之前用过 hugo&#xff0c;本次来分享一波&#xff0c;确实简单好用&#xff0c;可以持续使用&#xff0c;尤其是喜欢 GO语言的同学 hugo Hugo是一个用 Go语言 编写的静态网站生成器&#xff0c;可以快速地生成高效、安全和易于管理的静态网站。Hugo具有速度快、可定制性强、…

Hydra参数

kali的hyda参数 参数&#xff1a; hydra [[[-l LOGIN|-L FILE] [-p PASS|-P FILE]] | [-C FILE]] [-e ns][-o FILE] [-t TASKS] [-M FILE [-T TASKS]] [-w TIME] [-f] [-s PORT] [-S] [-vV] server service [OPT] -R 继续从上一次进度接着破解。 -S 采用SSL链接。 -s PORT 可通…