简单了解unordered_set和unordered_map底层

目录

1.哈希表(开散列)实现

   1.1 介绍模板参数

  1.2 代码实现 

2.迭代器

3.HASH转整形的类

4.unordered_map简单实现

5.unordered_map简单实现

6.验证

1.哈希表(开散列)实现

   1.1 介绍模板参数

//K:关键码
//T:保存数据,unordered_map是一个键值对,unordered_set是K
//KeyOfT:由于unordered_map和unordered_set保存值不同,KOFT是一个仿函数,取出关键码。。
//HashFunc:仿函数,将关键码Key不是整形类型转成整形。
//模板参数是由unordered_set和unordered_map传入的
template<class K, class T, class KeyOfT, class HashFunc>
class HashTable;

  1.2 代码实现 

namespace CH3
{//为了确保“K”可以取余template<class K>struct DefaultHashFunc{size_t operator()(const K& key){return (size_t)key;}};template<>struct DefaultHashFunc<string>{size_t operator()(const string& str){int sum = 0;for (auto& x : str){sum *= 131;sum += x;}return sum;}};//用“T”是因为不知道,传过来的是set还是maptemplate<class T>struct HashNode{T _date;//存数据HashNode<T>* _next;//保存下一个节点HashNode(const T& date):_date(date), _next(nullptr){}};// 前置声明template<class K, class T, class KeyOfT, class HashFunc>//因为在Iterator中使用了HashTable//所以需要提前声明,否则找不到class HashTable;template<class K, class T, class KeyOfT, class HashFunc>struct Iterator{typedef HashNode<T> Node;typedef Iterator<K, T, KeyOfT, HashFunc> Self;Node* _node;//保存节点是为了找到下一个节点HashTable<K, T, KeyOfT, HashFunc>* _pve;//保存哈希表的指针,当这一列找完了,可以找到下一列Iterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pve):_node(node),_pve(pve){}T& operator*(){return _node->_date;}T* operator->(){return &_node->_date;}Self& operator++(){KeyOfT kt;HashFunc ht;//返回下一迭代器if (_node->_next){_node = _node->_next;}else{size_t hashi = ht(kt(_node->_date)) % _pve->_table.size();//找当前节点在哈希表的下标hashi++;while (hashi < _pve->_table.size()){if (_pve->_table[hashi]){_node = _pve->_table[hashi];return *this;}else{hashi++;}}_node = nullptr;return *this;}return *this;}bool operator!=(const Self& pve){return _node != pve._node;}};template<class K, class T,class KeyOfT,class HashFunc = DefaultHashFunc<K>>class HashTable{typedef HashNode<T> Node;// 友元声明template<class K, class T, class KeyOfT, class HashFunc>friend struct Iterator;public:typedef Iterator<K, T, KeyOfT, HashFunc> iterator;iterator begin(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];if (cur){return iterator(cur, this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}HashTable(){_table.resize(10, nullptr);}~HashTable(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_table[i] = nullptr;}}bool insert(const T& kv){HashFunc ht;KeyOfT kt;//扩容if (_n == _table.size()){size_t newhashi = 2 * _table.size();vector<Node*> newtable;newtable.resize(newhashi, nullptr);//将旧表的每一列的节点移至新表中for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;size_t hashi = ht(kt(cur->_date)) % newtable.size();cur->_next = newtable[hashi];newtable[hashi] = cur;cur = next;}_table[i] = nullptr;}//新旧表之间的交换_table.swap(newtable);}//找到该节点,插入哈希表的第几列size_t hashi = ht(kt(kv)) % _table.size();Node* cur = new Node(kv);cur->_next = _table[hashi];_table[hashi] = cur;_n++;return true;}Node* Find(const K& key){HashFunc ht;KeyOfT kt;size_t hashi = ht(key) % _table.size();//找到该节点所在的列Node* cur = _table[hashi];//在这一列找是否存在while (cur){Node* next = cur->_next;if (ht(kt(cur->_date)) == key){return cur;}cur = next;}return nullptr;}//删除bool erase(const K& key){HashFunc ht;KeyOfT kt;size_t hashi = ht(key) % _table.size();Node* cur = _table[hashi];Node* prve = nullptr;while (cur){if (ht(kt(cur->_date)) == key){//头删//中间删if (prve == nullptr){_table[hashi] = cur->_next;}else{prve->_next = cur->_next;}delete cur;return true;}prve = cur;cur = cur->_next;}_n--;return false;}void print(){KeyOfT kt;for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];printf("%d->", i);while (cur){cout << kt(cur->_date) << "->";cur = cur->_next;}cout << "Null" << endl;}cout << endl;}private:vector<Node*> _table;size_t _n = 0;};
}

2.迭代器

这里实现的迭代器的++,是在哈希桶中找到第一个桶的,遍历完桶的结点,再找下一个桶遍历。

由于当遍历完当前桶要找下一个桶的位置。迭代器中还需要添加一个哈希桶指针,指向当前哈希桶。

 实现operator++操作:

       1.如果当前结点下一个结点不为空,走向下一个结点。

       2..如果当前结点的下一个结点为空,找到当前结点在哈希桶中的位置(利当前结点的值和哈希函数求出)。再在哈希桶里找下一个桶。这里会访问到哈希桶的成员变量(私有),需要将迭代器设为哈希桶的友元类。

	// 前置声明template<class K, class T, class KeyOfT, class HashFunc>//因为在Iterator中使用了HashTable//所以需要提前声明,否则找不到class HashTable;//迭代器template<class K, class T, class KeyOfT, class HashFunc>//由于使用了哈希表指针,使用也要加上模板参数struct Iterator{typedef HashNode<T> Node;typedef Iterator<K, T, KeyOfT, HashFunc> Self;Node* _node;//保存节点是为了找到下一个节点HashTable<K, T, KeyOfT, HashFunc>* _pve;//保存哈希表的指针,当这一列找完了,可以找到下一列Iterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pve):_node(node),_pve(pve){}T& operator*(){return _node->_date;}T* operator->(){return &_node->_date;}Self& operator++(){KeyOfT kt;HashFunc ht;if (_node->_next){_node = _node->_next;}else{size_t hashi = ht(kt(_node->_date)) % _pve->_table.size();//找当前节点在哈希表的下标hashi++;while (hashi < _pve->_table.size()){if (_pve->_table[hashi]){_node = _pve->_table[hashi];return *this;}else{hashi++;}}_node = nullptr;return *this;}return *this;}bool operator!=(const Self& pve){return _node != pve._node;}};

3.HASH转整形的类

    //装整形的类,默认整形,直接返回template<class K>struct DefaultHashFunc{size_t operator()(const K& key){return (size_t)key;}};//装整形的类,默认整形,直接返回template<>struct DefaultHashFunc<string>{size_t operator()(const string& str){int sum = 0;for (auto& x : str){sum *= 131;sum += x;}return sum;}};

  如果不是这两种,则需要在用户自己编写,传入模板参数。 

4.unordered_map简单实现

 这里只是简单实现了迭代器

 如想实现查找,删除,可直接调用哈希用的查找和删除,只需要改变返回值类型。

namespace CH
{template<class K,class V>class unordered_map{//仿函数(),用于返回 "K" 的值,写这个是为了取出map的“K”struct MapKeyOfT{const K& operator()(const pair<K,V>& kv){return kv.first;}};public://取一个类中的类,要加typenametypedef	typename CH3::HashTable<K,pair<K,V>, MapKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool insert(const pair<K,V>& kv){return _ht.insert(kv);}void print(){_ht.print();}private:CH3::HashTable<K, pair<K,V>, MapKeyOfT> _ht;};
}

5.unordered_map简单实现

namespace CH
{template<class K>class unordered_set{//仿函数struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef	typename CH3::HashTable<K, K, SetKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool insert(const K& key){return _ht.insert(key);}void print(){_ht.print();}private:CH3::HashTable<K, K, SetKeyOfT> _ht;};
}

6.验证

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

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

相关文章

[NSSCTF 2nd]php签到 详细题解

知识点: linux文件后缀名绕过 表单文件上传 pathinfo 函数 file_put_contents()函数 命令执行 代码审计: <?phpfunction waf($filename){$black_list array("ph", "htaccess", "ini");$ext pathinfo($filename, PATHINFO_EXTENSION…

《CUDA编程》11.CUDA流

本章将介绍CUDA流 CUDA程序的并行层次主要有两个&#xff1a;一个是核函数内部的并行&#xff0c;一个是核函数外部的并行&#xff0c;核函数外部的并行主要指&#xff1a; 核函数计算与数据传输之间的并行主机计算与数据传输之间的并行不同数据传输之间的并行核函数计算与主机…

操作系统期末|考研复习知识点汇总 - 持续更新

本文将根据个人学习进度对b站王道408课程以及题目考察的知识点进行整合&#xff0c;视频中详细的导图将会直接复用&#xff0c;并且将会对一些重点知识进行扩展以及一些思维导图的补充&#xff0c;(目前第三章内容正在整理中……由于第三章内容繁多且都是重点&#xff0c;习题量…

.NET Core WebApi第3讲:第一个WebApi项目、WebApi开发三种模型

一、.NEt Core 1、运行模板项目 1&#xff09;仍然有controllers&#xff0c;说明WebApi是基于MVC模式的&#xff0c;只是对比之下这里没有MVC中的views。 因为WebApi只会向前台发送数据&#xff0c;不会向前台发送HTML页面。 2、验证模板项目的api 1&#xff09;法1&#xf…

微服务之间调用,OpenFeign传递用户(RequestInterceptor接口)

场景&#xff1a;微服务之黑马商城项目-登录拦截器在网关完成用户的校验&#xff0c;并将用户信息&#xff08;用户id&#xff09;存入请求头&#xff0c;假设将购物车里面的商品进行结算就会生成订单并清空购物车&#xff0c;这里涉及到了交易服务模块远程调用购物车模块&…

单细胞数据分析(一):10X数据生成seurat数据对象

文章目录 介绍加载R包数据链接导入数据过滤细胞:移除双重细胞合并所有seurat数据对象输出结果系统信息介绍 在单细胞基因组学研究中,Seurat是一个流行的R包,用于单细胞基因表达数据的分析和探索。以下是如何从10X基因注释数据生成Seurat数据对象,并对该数据进行过滤的步骤…

RHCE的学习(8)

动态网站 lnmp&#xff08;LAMP&#xff09; 解析index.php界面 &#xff08;1&#xff09;预配&#xff0c;确保服务能够被访问 systemctl stop firewalld setenforce 0 &#xff08;2&#xff09;安装nginx服务 mount /dev/sr0 /mnt cat /etc/yum.repos.d/base.repo dnf …

NVR设备ONVIF接入平台EasyCVR视频融合平台智慧小区视频监控系统建设方案

一、方案背景 智慧小区构成了“平安城市”建设的基石。随着社会的进步&#xff0c;社区安全问题逐渐成为公众关注的热点。诸如高空抛物、乱丢垃圾、破坏车辆、入室盗窃等不文明行为和违法行为频繁出现。目前&#xff0c;许多小区的物业管理和安全防护系统仍然较为简单和陈旧&a…

UML总结

零&#xff1a;学习链接 UML_哔哩哔哩_bilibili 一&#xff1a;UML概述 二&#xff1a;类图 类图&#xff08;Class Diagram&#xff09;是统一建模语言&#xff08;UML&#xff09;中一种重要的图形表示&#xff0c;用于描述系统中的类及其之间的关系。它是面向对象设计中常…

软件已死,数据永生?

大数据产业创新服务媒体 ——聚焦数据 改变商业 你有没有注意到&#xff0c;你的生活正在被数据所支配&#xff1f; 我们看似在掌控自己的每一次点击、每一次搜索、每一个消费选择&#xff0c;但实际上&#xff0c;背后隐藏着庞大的数据网络。每一个点赞、每一次搜索&#xff…

Java非对称加密:RSA 数据加密与解密、数字签名与验签

Java常用的加密与解密系列文章: 《Java编码方式:Base64 编码与解码》 《Java消息摘要:MD5 验证数据完整性、密码的加密》 《Java消息摘要:SHA 验证数据完整性、密码的加密》 《Java对称加密:DES、3DES 数据加密标准》 《Java对称加密:AES 高级加密标准》 《Java非对称加密…

java质数的判断 C语言指针变量的使用

1. public static void main(String[] args) {Scanner scnew Scanner(System.in);System.out.println("请输入一个值");int num sc.nextInt();boolean flagtrue;for (int i2;i<num;i){if (num%i0){flagfalse;break;}}if (flag){System.out.println(num"是一…

深度学习:权重参数相关知识(深度学习入门:基于Python的理论与实现 (斋藤康毅)))

在神经网络的学习中&#xff0c;权重的初始值特别重要&#xff0c;经常关系到神经网络的学习能否成功。 第一点&#xff0c;权重初始值不能设置为0&#xff0c;严格说权重初始值不能设为同样的值&#xff0c;是因为在误差反向传播法中&#xff0c;所有权重值都会进行相同的更新…

云联网对等连接--实现内网互通

云联网 今天给大家介绍一款产品&#xff0c;腾讯云的云联网。 云联网&#xff1a;为您提供云上私有网络间&#xff08;VPC&#xff09;、VPC 与本地数据中心间&#xff08;IDC&#xff09;内网互联的服务&#xff0c;具备全网多点互联、路由自学习、链路选优及故障快速收敛等…

采用指针作为函数参数

在main.cpp里输入程序如下&#xff1a; #include <iostream> //使能cin(),cout(); #include <iomanip> //使能setbase(),setfill(),setw(), //setprecision(),setiosflags()和resetiosflags(); using namespace std; //告诉编译器使用std标准程序库; void…

kali——tcpdump的使用

目录 前言 使用方法 监听指定网卡 将抓取的数据包保存到指定文件 读取数据包 前言 定义&#xff1a;tcpdump 是 Linux 系统下的一个强大的命令行式数据包嗅探工具&#xff0c;它能够实时捕获网络接口上的数据包&#xff0c;并将这些数据包的头部信息或完整内容显示出来或保…

Java面向对象编程进阶(四)

Java面向对象编程进阶&#xff08;四&#xff09; 一、equals()方法的使用二、toString()方法的使用三、复习 一、equals()方法的使用 适用性&#xff1a;任何引用数据都可以使用。 自定义的类在没有重写Object中equals()方法的情况下&#xff0c;调用的就是Object类中声明的…

011:软件卸载工具TotalUninstall安装教程

摘要&#xff1a;本文详细介绍软件卸载工具TotalUninstall安装流程。 一、软件介绍 TotalUninstall是一款功能强大的卸载与清理工具&#xff0c;它能够彻底卸载不需要的应用程序&#xff0c;并清除相关的注册表项、文件残留和临时文件&#xff0c;确保系统干净无残留&#xff…

每日一题之电话号码的字母组合

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits "23" 输出&#…

2025选题|基于Hadoop的物品租赁系统的设计与实现

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…