unordered系列关联式容器--哈希结构详细讲解及使用示例

目录

  • unordered系列关联式容器
    • unordered_map
  • 哈希
    • 哈希概念
    • 哈希函数
      • 直接定址法:
      • 除留余数法:
    • 哈希冲突
    • 解决哈希冲突
      • 闭散列:
      • 开散列:

unordered系列关联式容器

之前讲解在C++98中STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2N log2N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同使用哈希结构。unordered_map、unordered_set、unordered_multimap和unordered_multiset

unordered_map

  1. unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
  2. 在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
  3. 在内部,unordered_map没有对<kye, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
  4. unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
  5. unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
  6. 它的迭代器只有前向迭代器。

第三方

  • 使用方式和map一样
    但操作性能相比map更高:O(1)的复杂度
	//使用方式和map一样unordered_map<int, int> m;//操作性能相比map更高:O(1)的复杂度m.insert(make_pair(1, 1));m[2] = 2;
  • 不同在于map遍历出来的值是有序的而unordered_map遍历出的值是无序的
    unordered_map只有正向迭代器,没有反向迭代器。
	for (int i = 3; i < 100; ++i){m[i] = i;}//相对于map/set,unordered_map/set只有正向迭代器//迭代器遍历,不是有序的unordered_map<int, int>::iterator it = m.begin();while (it != m.end()){cout << it->first << " ";}cout << endl;
  • equal_range:左闭右开的区间,查询key

由于是map,不允许Key重复,因此只输出了一个值3;如果是multimap可以有多个key值则会输出更多。

	//equal_range:auto range = m.equal_range(3);it = range.first;while (it != range.second){cout << it->first << " ";++it;}cout << endl;

哈希

unordered系列的关联式容器之所以效率比较高,是因为其底层使用了哈希结构。

哈希概念

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O( l o g 2 N log_2 N log2N),搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。
如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。
当向该结构中:

  • 插入元素

根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放

  • 搜索元素

对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)

哈希函数

直接定址法:

kx+b :适用于小范围数据的位置计算。如果数据范围过大会造成空间浪费。

除留余数法:

x%空间大小:通用
例如:数据集合{1,7,6,4,5,9};
哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小。
在这里插入图片描述
在这里插入图片描述

哈希冲突

对于两个数据元素的关键字 k i k_i ki k j k_j kj(i != j),有 k i k_i ki != k j k_j kj,但有:Hash( k i k_i ki) ==Hash( k j k_j kj),即:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。如上图4和14的哈希地址相同。
具有不同关键码而具有相同哈希地址的数据元素称为“同义词”

解决哈希冲突

闭散列:

  • 线性探测
    从计算的哈希位置开始,找第一个空闲的位置,存放数据。
//记录位置状态(哈希表内的数据删除相当于伪删除,因为查询数据如果查找到空余位就会停止查找,比如5,15,25,把15删掉后,查询25时走到15位置发现空余,会停止查找,因此在删除15时不能直接删除)
enum STATE
{EXIST,	//存在DELETE,	//删除EMPTY	//空
};template <class K, class V>
struct hashNode
{pair<k, V> _kv;STATE _state = EMPTY;
};//顺序表实现hash
template <class K, class V>
class HashTable
{
public:typedef HashNode<K, V> Node;HashTable(size_t n = 10):_hTable(n), _size(0){}bool insert(const pair<K, V>& kv){//0.检查容量checkCapacity();//1.计算哈希位置int idx = kv.first % _hTable.size();//2.判断key是否存在while (_hTable[idx]._state != EMPTY){//如果当前位置数据有效,且key相同,插入失败if (_hTable[idx]._state == EXIST && kv.first == _hTable[idx]._kv.first){return false;}//继续搜索++idx;if (idx == _hTable.size())idx = 0;}//插入_hTable[idx] = kv;_hTable[idx]._state = EXIST;++_size;return true;}void checkCapacity(){//负载因子:<1 有效元素个数/容量大小//负载因子越小可存储的元素就越多,可也浪费的越多,因此权衡取:0.7if (_hTable.size() == 0 || _size * 10 / _hTable.size() >= 7){//开新表int newC = _hTable.size() == 0 ? 10 : 2 * _hTable.size();HashTable<K, V> newHt(newC);for (int i = 0; i < _hTable.size(); ++i){//插入状态为exist的数据if (_hTable[i]._state == EXIST){newHt.insert(_hTable[i]._kv);}}Swap(newHt);}}void Swap(HashTable<K, V>& Ht){swap(_hTable, Ht._hTable);swap(_size, Ht._size);}Node* find(const K& key){//计算位置int idx = key % _hTable.size();while (_hTable[idx]._state != EMPTY){if (_hTable[idx]._state == EXIST && key == _hTable[idx]._kv.first){return &_hTable[idx];}++idx;if (idx == _hTable.size()){idx = 0;}}return nullptr;}bool erase(const K& key){Node* node = find(key);if (node){//假删除--_size;node->_state = DELETE;return true;}return false;}private:vector<Node> _hTable;size_t _size;	//有效元素的个数
};void test()
{HashTable<int, int> ht;ht.insert(make_pair(1, 1));ht.insert(make_pair(14, 14));ht.insert(make_pair(16, 16));ht.insert(make_pair(11, 11));cout << ht.erase(11) << endl;cout << ht.erase(100) << endl;
}
  • 二次探测

开散列:

持续更新~~

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

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

相关文章

Nginx域名重定向(如何访问的域名和实际的数据请求路径不同,可解决前端跨域)

感情需要被抑制&#xff0c;不能泛滥… 当需要将一个域名重定向到另一个域名并且用户仍然看到原始域名时&#xff0c;Nginx是一个强大的工具。这种场景通常涉及到反向代理或重写URL的技巧。在本篇博客中&#xff0c;我们将详细介绍如何使用Nginx来实现这个目标&#xff0c;以及…

精品基于Python的考场考试分配规划系统

《[含文档PPT源码等]精品基于Python的考场分配规划系统的设计与实现》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技…

ubuntu(18.04) 安装 blast 并在php中调用

1、下载 https://ftp.ncbi.nlm.nih.gov/blast/executables/blast/LATEST/2、解压&#xff0c;配置环境变量 tar zvxf ncbi-blast-2.14.1-x64-linux.tar.gz解压后改名为 blast 配置环境变量&#xff0c;可以不配置 使用的时候直接绝对路径使用&#xff08;本次使用绝对路径&am…

LInux之在同一Tomcat下使用不同的端口号访问不同的项目

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《LInux实战开发》。&#x1f3af;&#x1f3af; …

Failed to launch task: 文件”Setup”不存在 Mac安装Adobe软件报错解决方案

在安装 Adobe 软件时&#xff0c;软件提示 Failed to launch task: 文件”Setup”不存在 &#xff0c;这个时候怎么处理呢&#xff1f; 解决方法如下&#xff1a; 1、安装 AnitCC 或 或 Creative Cloud 环境&#xff0c;保证软件所需要的环境 2、如果安装后也不起作用&#x…

知识图谱与大模型结合方法概述

《Unifying Large Language Models and Knowledge Graphs: A Roadmap》总结了大语言模型和知识图谱融合的三种路线&#xff1a;1&#xff09;KG增强的LLM&#xff0c;可在LLMs的预训练和推理阶段引入KGs&#xff1b;2&#xff09;LLM增强KG&#xff0c;LLM可用于KG构建、KG emb…

CondConv 动态卷积学习笔记 (附代码)

论文地址:https://arxiv.org/abs/1904.04971 代码地址&#xff1a;https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet/condconv 1.是什么&#xff1f; CondConv是一种条件参数卷积&#xff0c;也称为动态卷积&#xff0c;它是一种即插即用的模块&…

服务器带宽忽然暴增,不停的触发告警

问题&#xff1a; 线上环境&#xff0c;服务器的外网下行带宽达到某个阈值&#xff0c;触发告警&#xff0c;查了下服务器的带宽监控信息&#xff0c;是从某个时间开始突然串上去的&#xff0c;然后监控图形非常有规律&#xff0c;都是每秒达到顶峰后&#xff0c;又立马下去了…

2023年十大地推网推拉新接单平台,都是一手单和官方渠道

2023年做拉新推广的地推人员&#xff0c;一定不要错过这十个接单平台&#xff0c;助你轻松找到一手单&#xff0c;这10个平台分别是&#xff1a; &#xff08;主推&#xff1a;聚量推客&#xff09; 我们也拿到了一手邀请码&#xff1a;000000 1&#xff1a;聚量推客 “聚量推…

震惊!乐歌IE7和T5S价格相差2000块,竟只是没有它

前段时间的乐歌电梯广告相信大家都有看过&#xff0c;广告中的主角就是乐歌旗舰款学习桌——IE7。目前在天猫和京东的日常售价是7299&#xff0c;这个价格对于大部分的普通家庭都承受不住&#xff0c;乐歌也考虑到这个问题&#xff0c;所以近期不是新出了一款叫做T5S的学习桌型…

【Redis】认识Redis-特点特性应用场景对比MySQL重要文件及作用

文章目录 认识redisredis的主要特点redis的特性&#xff08;优点&#xff09;redis是单线程模型&#xff0c;为什么效率这么高&#xff0c;访问速度这么快redis应用场景redis不可以做什么MySQL和Redis对比启动RedisRedis客户端Redis重要文件及作用 认识redis redis里面相关的小…

opencv 连通域操作示例代码记录connectedComponentsWithStats()函数示例

void CrelaxMyFriendDlg::OnBnClickedOk() {hdc this->GetDC()->GetSafeHdc();// TODO: 在此添加控件通知处理程序代码string imAddr "c:/Users/actorsun/Pictures/";string imAddr1 imAddr"rice.png";Mat relax1, positive;relax1 imread(imAdd…

药监局瑞数6 分析 2023版

网站地址 aHR0cHM6Ly93d3cubm1wYS5nb3YuY24veWFvcGluL3lwamdkdC9pbmRleC5odG1s 清除cookie 选中脚本调试 第一次获取的结果ts 第二次获取的结果是一个294cc83.js&#xff0c;可以固定 第三次获取的结果 content和ts属性每次都要换,还有ts属性一定要和content对应,否则你怎么…

【Mybatis-Plus】代码生成器

目录 安装插件 数据库建表 Other Config Database Code Generator 根据创建好的数据库表&#xff0c;来直接生成代码 安装插件 数据库建表 Other 点开之后有两个功能 1.数据库配置 2.代码生成 Config Database 首先点开这个配置数据库 Code Generator 配置完数据库…

算法的空间复杂度

一、空间复杂度定义 空间复杂度是一个数学表达式&#xff0c;是对一个算法在运行过程中临时占用存储空间大小的量度 二、空间复杂度的表示方法 大O渐进表示法 空间复杂度不是计算程序占用了多少字节的空间&#xff0c;因为这种计算没有意义。空间复杂度计算的是程序中变量的…

HTTP和HTTPS本质区别——SSL证书

HTTP和HTTPS是两种广泛使用的协议&#xff0c;尽管它们看起来很相似&#xff0c;但是它们在网站数据传输的安全性上有着本质上的区别。 HTTP是明文传输协议&#xff0c;意味着通过HTTP发送的数据是未经加密的&#xff0c;容易受到拦截、窃听和篡改的风险。而HTTPS通过使用SSL或…

外汇天眼:10月客诉前十榜单出炉,差评不断所谓何因?

纵观整个10月的天眼客诉排行榜&#xff0c;可以发现此次名单基本上都是无监管、成立时间短的“新”外汇平台&#xff0c;其中无法出金依旧仍是客诉的关键来源&#xff01; 接下来&#xff0c;就跟着天眼君一起来看看是哪些“新”平台上榜天眼客诉榜&#xff01; 具体客诉排行榜…

批量修改文件名称(现学现卖版)

目录 一、复制所有文件路径二、批量修改 一、复制所有文件路径 ctrlA选中所有文件&#xff0c;点击主页&#xff0c;复制路径 粘贴到excal表格中 添加新文件名 组合命令&#xff0c;插入函数CONCATENATE ren空格<旧文件名>空格<新文件名><后缀名> …

java如何获取调用接口的ip?

获取调用者的ip 场景&#xff1a;想知道哪个ip访问的某个接口时&#xff0c;就需要打印出来看看&#xff0c;这时就可以使用这个方法了。 案例&#xff1a; //HttpServletRequest 入参加上,请求对象public ForkResponse queryXXX(RequestBody XXXX xxxx, HttpServletRequest …

docker离线部署

docker离线部署 1、目的 在可以连接互联网的情况下&#xff0c;可以在线安装Docker《Linux下Docker安装部署》&#xff0c;如果遇到内网服务器就没有办法进行在线安装&#xff0c;那么需要使用离线安装的方法。 2、下载安装包 创建工作文件夹&#xff1a; mkdir /opt/dock…