当前位置: 首页 > news >正文

unordered_map和set

前言:本篇文章继续分享新的容器unordered_map和set。前边我们分享过map和set,其底层为红黑树,而unordered_map和set的底层则为哈希表,因此在unordered_map和set的实现中,我们可以效仿许多在map和set的中就分享过的一些知识,所以在本篇文章中,就不对分享过的知识进行重复讲解。

而unordered_map和set与map和set的区别,即为红黑树和哈希表的区别


目录

一.修改hash

二.迭代器

三.完整代码

1.unordered_map

2.unordered_set

四.总结


一.修改hash

我们所实现的普通哈希表肯定是无法直接拿来作为unordered_map和set的底层代码的,所以我们需要对其进行优化修改,完整代码如下:

template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};struct HashStringFunc
{size_t operator()(const string& s){size_t hash = 0;for (auto e : s){hash += e;}return hash;}
};namespace hash_bucket
{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}};//前置声明template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class KeyOfT, class Hash>struct __Iterator{typedef HashNode<T> Node;typedef __Iterator<K, T, KeyOfT, Hash> Self;Node* _node;HashTable<K, T, KeyOfT, Hash>* _pht;__Iterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht):_node(node),_pht(pht){}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}Self& operator++(){if (_node->_next)//当前桶没走完,找到下一个节点_node = _node->_next;else{//当前桶走完了,找下一个不为空的桶的第一个节点KeyOfT kot;Hash hs;size_t i = hs(kot(_node->_data)) % _pht->_tables.size();i++;for (; i < _pht->_tables.size(); i++){if (_pht->_tables[i])break;}if (i == _pht->_tables.size())//所有桶都走完了,置nullptr_node = nullptr;else_node = _pht->_tables[i];}return *this;}bool operator!=(const Self& s){return _node != s._node;}};template<class K, class T, class KeyOfT, class Hash>class HashTable{typedef HashNode<T> Node;public://友元template<class K, class T, class KeyOfT, class Hash>friend struct __Iterator;typedef __Iterator<K, T, KeyOfT, Hash> iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return iterator(cur, this);}}return end();}iterator end(){return iterator(nullptr, this);}HashTable(){_tables.resize(10, nullptr);_n = 0;}~HashTable(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}//插入pair<iterator,bool> Insert(const T& data){KeyOfT kot;Hash hs;//判断是否存在iterator it = Find(kot(data));if (it != end())return make_pair(it,false);//扩容if (_n == _tables.size()){vector<Node*> newtables(_tables.size() * 2, nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;size_t hashi = hs(kot(cur->_data)) % newtables.size();cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newtables);}size_t hashi = hs(kot(data)) % _tables.size();Node* newnode = new Node(data);//头插newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(iterator(newnode,this), false);}//寻找iterator Find(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key)return iterator(cur,this);cur = cur->_next;}return end();}bool Erase(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];Node* prev = nullptr;while (cur){if (kot(cur->_data) == key){//删除的是第一个节点if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;}else{prev = cur;cur = cur->_next;}}return false;}private:vector<Node*> _tables;//指针数组size_t _n;};}

这其中包括只对key进行操作的修改,以及当插入的元素为string型时对其进行的特殊处理。都是我们之前所分享过的知识。下面我们重点来看迭代器


二.迭代器

先来看整体结构:

template<class K, class T, class KeyOfT, class Hash>struct __Iterator{typedef HashNode<T> Node;typedef __Iterator<K, T, KeyOfT, Hash> Self;Node* _node;HashTable<K, T, KeyOfT, Hash>* _pht;__Iterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht):_node(node),_pht(pht){}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}Self& operator++(){if (_node->_next)//当前桶没走完,找到下一个节点_node = _node->_next;else{//当前桶走完了,找下一个不为空的桶的第一个节点KeyOfT kot;Hash hs;size_t i = hs(kot(_node->_data)) % _pht->_tables.size();i++;for (; i < _pht->_tables.size(); i++){if (_pht->_tables[i])break;}if (i == _pht->_tables.size())//所有桶都走完了,置nullptr_node = nullptr;else_node = _pht->_tables[i];}return *this;}bool operator!=(const Self& s){return _node != s._node;}};

其中最为重要的莫过于++运算符的重载,因为我们的哈希表是闭散列的哈希桶,所以是以指针数组作为底层。

在执行++操作时,需要先判断当前节点的next是否存在,存在就直接为next节点,不存在就说明当前节点已经是其所属的桶里的最后一个节点,那么接下来的操作就是去寻找下一个不为空的桶的第一个节点

此时我们需要先计算出当前节点在数组中的位置,然后通过循环判断其后边的位置是否存在桶如果存在,就返回新桶的第一个节点,不存在,就说明所有的桶都走完了,此时返回空指针nullptr


三.完整代码

1.unordered_map

#include"hash.h"
namespace Myunordered_map
{template<class K,class V, class Hash = HashFunc<K>>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;};
}

2.unordered_set

#include"hash.h"
namespace Myunordered_set
{template<class K, class Hash = HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}pair<iterator, bool> insert(const K& key){return _ht.Insert(key);}private:hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;};
}

四.总结

关于unordered_map和set就分享这么多,通过前边的知识的分享和掌握,unordered_map和set的实现也是如鱼得水。

喜欢本篇文章的小伙伴记得一键三连,我们下期再见!

 

相关文章:

unordered_map和set

前言&#xff1a;本篇文章继续分享新的容器unordered_map和set。前边我们分享过map和set&#xff0c;其底层为红黑树&#xff0c;而unordered_map和set的底层则为哈希表&#xff0c;因此在unordered_map和set的实现中&#xff0c;我们可以效仿许多在map和set的中就分享过的一些…...

java:运用字节缓冲输入流将文件中的数据写到集合中

代码主要是将文本文件中的数据写到集合中&#xff0c;运用到的是java字节缓冲输入流的知识点。 public static void main(String[] args) throws IOException {//创建字符缓冲流输入对象BufferedReader bufferedReader new BufferedReader(new FileReader("student.txt&q…...

【机器学习】支持向量机与主成分分析在机器学习中的应用

文章目录 一、支持向量机概述什么是支持向量机&#xff1f;超平面和支持向量大边距直觉 二、数据预处理与可视化数据集的基本信息导入必要的库加载数据集数据概况数据可视化特征对的散点图矩阵类别分布条形图平均面积与平均光滑度的散点图变量之间的相关性热图 三、模型训练&am…...

SpringBoot项目架构实战之“网关zuul搭建“

第三章 网关zuul搭建 前言&#xff1a; 1、主要功能 zuul主要提供动态路由&#xff08;内置ribbon实现&#xff09;和过滤&#xff08;可以做统一鉴权过滤器、灰度发布过滤器、黑白名单IP过滤器、服务限流过滤器&#xff08;可以配合Sentinel实现&#xff09;&#xff09;功能…...

发挥储能系统领域优势,海博思创坚定不移推动能源消费革命

随着新发展理念的深入贯彻&#xff0c;我国正全面落实“双碳”目标任务&#xff0c;通过积极转变能源消费方式&#xff0c;大幅提升能源利用效率&#xff0c;实现了以年均约3.3%的能源消费增长支撑了年均超过6%的国民经济增长。这一成就的背后&#xff0c;是我国能源结构的持续…...

matlab R2016b安装cplex12.6,测试时cplex出现出现内部错误的解决方法

问题场景 网上搜索matlabyalmipcplex的安装教程&#xff0c;跟着步骤操作即可&#xff0c;假如都安装好了&#xff0c;在matlab中测试安装是否成功&#xff0c;出现以下问题&#xff1a; 1、matlab中设置路径中添加了yalmip和cplex路径&#xff0c;在命令窗口中输入yalmiptest…...

C#中的Dictionary

Dictionary<TKey, TValue> 是一个泛型集合&#xff0c;它存储键值对&#xff08;key-value pairs&#xff09;&#xff0c;其中每个键&#xff08;key&#xff09;都是唯一的。这个集合类提供了快速的数据插入和检索功能&#xff0c;因为它是基于哈希表实现的。 注意 ke…...

VSCode中多行文本的快速前后缩进

快捷键 VSCode提供了一组快捷键&#xff0c;用于快速调整选中文本行的缩进。 增加缩进&#xff08;向前缩进&#xff09;&#xff1a;在Windows和Linux上按 Tab 键&#xff0c;在Mac上按 ⇧⇥&#xff08;Shift Tab&#xff09;。减少缩进&#xff08;向后缩进&#xff09;&…...

C# 8.0 新语法的学习和使用

C# 8.0 是微软在 2019 年 9 月 23 日随 .NET Core 3.0 一同发布的一个重要版本更新&#xff0c;带来了许多新的语言特性和改进。本文将详细介绍 C# 8.0 的新语法&#xff0c;并通过实际应用案例展示这些新特性的使用方法。 目录 1. 可空引用类型 2. 异步流 3. 默认接口方…...

数据结构——约瑟夫环C语言链表实现

约瑟夫环问题由古罗马史学家约瑟夫&#xff08;Josephus&#xff09;提出&#xff0c;他参加并记录了公元66—70年犹太人反抗罗马的起义。在城市沦陷之后&#xff0c;他和40名死硬的将士在附近的一个洞穴中避难。起义者表示“宁为玉碎不为瓦全”&#xff0c;约瑟夫则想“留得青…...

【MyBatis】——入门基础知识必会内容

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…...

react父调用子的方法,子调用父的方法

父调用子的方法 // 子组件 import React, { useRef, useEffect } from react;const ChildComponent ({ childMethodRef }) > {const childMethod useRef(null);useEffect(() > {childMethodRef.current childMethod;}, []);const someMethod () > {console.log(子…...

C#知识|账号管理系统:UI层-添加账号窗体设计思路及流程。

哈喽,你好啊,我是雷工! 前边练习过详情页窗体的设计思路及流程: 《C#知识|上位机UI设计-详情窗体设计思路及流程(实例)》 本节练习添加账号窗体的UI设计,以下为学习笔记。 01 效果展示 02 添加窗体 在UI层添加Windows窗体,设置名称为:FrmAddAcount.cs 设置窗体属…...

【机器学习】初学者经典案例(随记)

&#x1f388;边走、边悟&#x1f388;迟早会好 一、概念 机器学习是一种利用数据来改进模型性能的计算方法&#xff0c;属于人工智能的一个分支。它旨在让计算机系统通过经验自动改进&#xff0c;而不需要明确编程。 类型 监督学习&#xff1a;使用带标签的数据进行训练&…...

进阶版智能家居系统Demo[C#]:整合AI和自动化

引言 在基础智能家居系统的基础上&#xff0c;我们将引入更多高级功能&#xff0c;包括AI驱动的自动化控制、数据分析和预测。这些进阶功能将使智能家居系统更加智能和高效。 目录 高级智能家居功能概述使用C#和AI实现智能家居自动化实现智能照明系统的高级功能 自动调节亮度…...

IC后端设计中的shrink系数设置方法

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在一些成熟的工艺节点通过shrink的方式(光照过程中缩小特征尺寸比例)得到了半节点,比如40nm从45nm shrink得到,28nm从32nm shrink得到,由于半节点的性能更优异,成本又低,漏电等不利因素也可以…...

在NVIDIA Jetson平台离线部署大模型

在NVIDIA Jetson平台离线部署大模型&#xff0c;开启离线具身智能新纪元。 本项目提供一种将LMDeploy移植到NVIDIA Jetson系列边缘计算卡的方法&#xff0c;并在Jetson计算卡上运行InternLM系列大模型&#xff0c;为离线具身智能提供可能。 最新新闻&#x1f389; [2024/3/1…...

51单片机嵌入式开发:8、 STC89C52RC 操作LCD1602原理

STC89C52RC 操作LCD1602原理 1 LCD1602概述1.1 LCD1602介绍1.2 LCD1602引脚说明1.3 LCD1602指令介绍 2 LCD1602外围电路2.1 LCD1602接线方法2.2 LCD1602电路原理 3 LCD1602软件操作3.1 LCD1602显示3.2 LCD1602 protues仿真 4 总结 1 LCD1602概述 1.1 LCD1602介绍 LCD1602是一种…...

数字化时代的供应链管理综合解决方案

目录 引言背景与意义供应链管理综合解决方案的目标 &#x1f4c4;供应链管理系统主要功能系统优势 &#x1f4c4;物流管理系统主要功能系统优势 &#x1f4c4;订单管理系统主要功能应用场景 &#x1f4c4;仓储管理系统系统亮点主要功能系统优势 &#x1f4c4;商城管理系统主要功…...

CentOS 安装 annie/lux,以及 annie/lux 的使用

annie 介绍 如果第一次听到 annie 想必都会觉得陌生&#xff0c;annie 被大家称为视频下载神器&#xff0c;annie 作者介绍说可以下载抖音、哔哩哔哩、优酷、爱奇艺、芒果TV、YouTube、Tumblr、Vimeo 等平台的视频。 githup&#xff1a;https://github.com/pingf/annie 支持…...

拥抱UniHttp,规范Http接口对接之旅

前言 如果你项目里还在用传统的编程式Http客户端比如HttpClient、Okhttp去直接对接第三方Http接口&#xff0c; 那么你项目一定充斥着大量的对接逻辑和代码&#xff0c; 并且针对不同的对接渠道方需要每次封装一次调用的简化&#xff0c; 一旦封装不好系统将会变得难以维护&am…...

Python 给存入 Redis 的键值对设置过期时间

Redis 是一种内存中的数据存储系统&#xff0c;与许多传统数据库相比&#xff0c;它具有一些优势&#xff0c;其中之一就是可以设置数据的过期时间。通过 Redis 的过期时间设置&#xff0c;可以为存储在 Redis 中的数据设置一个特定的生存时间。一旦数据到达过期时间&#xff0…...

在linux中安装docker

文章目录 1、安装依赖2、安装docker的下载源3、安装docker4、设置Docker服务开机自启 1、安装依赖 sudo yum install -y yum-utils2、安装docker的下载源 sudo yum-config-manager \--add-repo \https://download.docker.com/linux/centos/docker-ce.repohttps://download.do…...

【JVM-04】线上CPU100%

【JVM-04】线上CPU100% 1. 如何排查2. 再举一个例子 1. 如何排查 ⼀般CPU100%疯狂GC&#xff0c;都是死循环的锅&#xff0c;那怎么排查呢&#xff1f;先进服务器&#xff0c;⽤top -c 命令找出当前进程的运⾏列表按⼀下 P 可以按照CPU使⽤率进⾏排序显示Java进程 PID 为 2609…...

try catch 解决大问题

项目开发中遇到一个棘手的bug&#xff0c;react前端项目独自运行时一切正常&#xff0c;但是把项目集成到使用wujie的大平台微前端项目中之后&#xff0c;突然有个地方无故报错&#xff0c;导致程序运行停止&#xff0c;后续的方法不再执行。报错如下&#xff1a; DOMExceptio…...

手动解析Collection

即将被解析的json {"collection": {"templates": [{"data": [{"name": "plantCode","value": "MSHG_KFXHS02"}, {"name": "details","value": [{"plantMedicament…...

list模拟实现【C++】

文章目录 全部的实现代码放在了文章末尾准备工作包含头文件定义命名空间类的成员变量为什么节点类是用struct而不是class呢&#xff1f;为什么要写get_head_node? 迭代器迭代器在list类里的实例化和重命名普通迭代器operator->()的作用是什么&#xff1f; const迭代器反向迭…...

nginx正向代理、反向代理、负载均衡

nginx.conf nginx首要处理静态页面 反向代理 动态请求 全局模块 work processes 1; 设置成服务器内核数的两倍&#xff08;一般不不超过8个超过8个反而会降低性能一般4个 1-2个也可以&#xff09; netstat -antp | grep 80 查端口号 *1、events块&#xff1a;* 配置影响ngi…...

matlab 有倾斜的椭圆函数图像绘制

matlab 有倾斜的椭圆函数图像绘制 有倾斜的椭圆函数图像绘制xy交叉项引入斜线负向斜线成分正向斜线成分 x^2 y^2 xy 1 &#xff08;负向&#xff09;绘制结果 x^2 y^2 - xy 1 &#xff08;正向&#xff09;绘制结果 有倾斜的椭圆函数图像绘制 为了确定椭圆的长轴和短轴的…...

PTK是如何加密WLAN单播数据帧的?

1. References WLAN 4-Way Handshake如何生成PTK&#xff1f;-CSDN博客 2. 概述 在Wi-Fi网络中&#xff0c;单播、组播和广播帧的加密算法是由AP决定的。其中单播帧的加密使用PTK密钥&#xff0c;其PTK的密钥结构如下图所示&#xff1a; PTK的组成如上图所示&#xff0c;由K…...

b2b官网seo/seo接单

1&#xff0e; Windows SEH 与 C Exception 1) Windows SEH 结构化异常 结构化异常是Windows 操作系统提供的与语言无关的异常处理机制&#xff0c; SHE使用Win32API中的RaiseException()函数来抛出异常&#xff0c;在VC中使用关键字__try和关键字__except来…...

怎么做网站免费的/比百度强大的搜索引擎

目标如题&#xff0c;希望在anaconda的某个特定环境中把此环境的gcc版本降级为4.8.* 首先进入anaconda官网&#xff0c;在里面搜索gcc。 会出现很多版本&#xff0c;找到想要的版本&#xff0c;也可以搜索类似gcc_4&#xff0c;gcc4&#xff0c;gcc-4等&#xff08;这个搜索算…...

wordpress文章禁止搜索/百度网盘电脑版官网

OpenFeign 概述 Feign是一个声明式的web服务客户端&#xff0c;让编写web服务客户端变得非常容易&#xff0c;只需创建一个接口并在接口上添加Feign的注解即可 为什么要使用OpenFeign 前面在使用Ribbon RestTemplate时&#xff0c;利用RestTemplate对http请求进行了封装处理&…...

网站怎样做wap端/国内新闻最新消息十条

第1关:通信簿.csv文件进行查询 本关任务:编写函数cztxb,实现根据姓名对通信录.csv文件查询。输入查询的姓名,若文件中存在该人,显示其信息;当查询的姓名不存在时,显示“查无此人”。 #当前位置的sc文件夹下csv格式文件“通信簿”, #该文件每行记录一个姓名、住址、电话…...

网站开发 . 漫游指南/企业培训课程名称大全

目录 贝叶斯定理 贝叶斯分类 朴素贝叶斯分类器 贝叶斯网络 VS 朴素贝叶斯 贝叶斯网络 条件概率表集合 贝叶斯网络的构造…...

电脑做网站空间/windows优化大师是系统软件吗

对于python列表里元素的操作主要分为以下几个方面&#xff1a; 1、向列表里面加元素&#xff1b; 向python列表里面添加元素主要有三种方法&#xff1a; &#xff08;1&#xff09;append&#xff08;&#xff09; append()对于列表的操作主要实现的是在特定的列表最后添加一个…...