【C++进阶07】哈希表and哈希桶

在这里插入图片描述

一、哈希概念

顺序结构以及平衡树中
元素关键码与存储位置没有对应关系
因此查找一个元素
必须经过关键码的多次比较
顺序查找时间复杂度为O(N)
平衡树中为树的高度,即O( l o g 2 N log_2 N log2N)

搜索效率 = 搜索过程中元素的比较次数
理想的搜索方法:不经任何比较
一次直接从表中获取想要的元素

构造一种存储结构
通过某种函数(hashFunc)使元素的存储位置
与它的关键码之间建立一一映射的关系
就能在查找时通过该函数直接找到该元素

向该结构中:
插入元素:
根据待插入元素的关键码
以此函数计算出该元素的存储位置并按此位置
进行存放
搜索元素:
对元素的关键码进行同样的计算
把求得的函数值当做元素的存储位置
在结构中按此位置取元素比较
若关键码相等,则搜索成功

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

例如:
数据集合{1,7,6,4,5,9};
哈希函数设置为:
hash(key) = key % capacity;
capacity:
存储元素底层空间总的大小

在这里插入图片描述

二、哈希冲突

不同关键字通过相同的哈希函数
计算出相同的哈希地址
该种现象称为哈希冲突或哈希碰撞

把具有不同关键码
而具有相同哈希地址的数据元素称为“同义词”

11、21、31…数据经过哈希函数计算都为1
都插入在下标为1的地方便会冲突

在这里插入图片描述

三、哈希函数

引起哈希冲突的一个原因可能是:
哈希函数设计不够合理

哈希函数设计原则:

  • 哈希函数的定义域必须包括
    需要存储的全部关键码
    而如果散列表允许有m个地址时
    其值域必须在0到m-1之间
  • 哈希函数计算出来的地址能均匀分布在
    整个空间中
  • 哈希函数应该比较简单

常用哈希函数:

  1. 直接定址法
    取关键字的某个线性函数为散列地址:
    Hash(Key)= A*Key + B
    优点:简单、均匀
    缺点:需要事先知道关键字的分布情况
    使用场景:适合查找比较小且连续的情况
    面试题:字符串中第一个只出现一次字符

  2. 除留余数法
    设散列表中允许的地址数为m
    取一个不大于m
    但最接近或等于m的质数p作为除数
    按照哈希函数:
    Hash(key) = key% p(p<=m)
    将关键码转换成哈希地址

四、哈希冲突解决

解决哈希冲突两种常见方法:
闭散列和开散列

4.1 闭散列

闭散列:也叫开放定址法
当发生哈希冲突时
如果哈希表未被装满
说明哈希表中必然还有空位置
那么可以把key存放到
冲突位置的“下一个” 空位置中去

那如何寻找下一个空位置呢?

  1. 线性探测
    从发生冲突的位置开始
    依次向后探测
    直到寻找到下一个空位置为止

在这里插入图片描述
线性探测优点:实现简单

线性探测缺点:一旦发生哈希冲突
所有的冲突连在一起,容易产生数据“堆积”
即:不同关键码占据了可利用的空位置
使得寻找某关键码的位置需要许多次比较
导致搜索效率降低

  1. 二次探测

线性探测的缺陷是
产生冲突的数据堆积在一块
这与其找下一个空位置有关系
因为找空位置的方式就是挨着往后逐个去找

因此二次探测为了避免该问题
找下一个空位置的方法为:
H i H_i Hi = ( H 0 H_0 H0 + i 2 i^2 i2 )% m
或者: H i H_i Hi = ( H 0 H_0 H0 - i 2 i^2 i2 )% m
其中:i = 1,2,3…, H 0 H_0 H0是通过
散列函数Hash(x)对元素的关键码 key
进行计算得到的位置,m是表的大小

研究表明:当表的长度为质数且表装载因子
a不超过0.5时,新的表项一定能够插入
而且任何一个位置都不会被探查两次
因此只要表中有一半的空位置
就不会存在表满的问题
在搜索时可以不考虑表装满的情况
但在插入时必须确保表的装载因子a不超过
0.5,如果超出必须考虑增容
因此:比散列最大的缺陷就是空间利用率
比较低,这也是哈希的缺陷

4.2 开散列

开散列法又叫链地址法(开链法)
首先对关键码集合用散列函数计算散列地址
具有相同地址的关键码归于同一子集合
每一个子集合称为一个桶
各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中

如图:
将哈希地址相同的元素链接在同一个桶下面
在这里插入图片描述
在实际应用中
开散列比闭散列更实用

  1. 哈希桶负载因子更大
    空间利用率高
  2. 极端情况也有解决方案

哈希桶极端情况:
所有元素在同一个桶
为了避免这种情况
当桶超过一定高度
将该桶转换为红黑树结构

五、哈希桶的模拟实现

5.1 基本框架

namespace HashBucket // 哈希桶
{	template <class K, class V>struct HashNode{pair<K, V> _kv;HashNode<K, V>* _next; // 单链表的方式链接HashNode(const pair<K, V>& kv): _next(nullptr), _kv(kv){}};template <class K, class V>class HashTable{typedef HashNode<K, V> Node;public:private:vector<Node*> _tables;size_t _n = 0; // 存储的有效数据个数 };
}

5.2 插入元素

哈希桶的增容
若哈希表的大小为0
将哈希表的初始值设置为10

若哈希表的负载因子等于1
创建一个新表,大小是原表的两倍
用新表的哈希函数计算旧表的每个
元素在新表的映射位置
将旧表的每个元素头插进新表

bool Insert(const pair<K, V>& kv)
{// 去重, 插入之前先查找有没有相同的元素if (Find(kv.first))return false;// 负载因子 == 1时扩容if (_n == _tables.size()){// 哈希表大小为0,将哈希表初始值设为10size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;vector<Node*> newtables(newsize, nullptr);for (auto& cur : _tables){while (cur) // current不为空, 把挂着的数据一个一个移到新表{Node* next = cur->_next;size_t hashi = cur->_kv.first % newtables.size();// 头插到新表cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}}_tables.swap(newtables);}size_t hashi = kv.first % _tables.size();// 头插Node* newnode = new Node(kv);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return true;
}Node* Find(const K& key)
{if (_tables.size() == 0)return nullptr;size_t hashi = key % _tables.size();Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key){return cur;}cur = cur->_next;}return nullptr;
}bool Erase(const K& key)
{size_t hashi = key % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;return true;}else{prev = cur;cur = cur->_next;}}return false;
}

✨✨✨✨✨✨✨✨
本篇博客完,感谢阅读🌹
如有错误之处可评论指出
博主会耐心听取每条意见
✨✨✨✨✨✨✨✨

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

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

相关文章

测试不拘一格——掌握Pytest插件pytest-random-order

在测试领域&#xff0c;测试用例的执行顺序往往是一个重要的考虑因素。Pytest插件 pytest-random-order 提供了一种有趣且灵活的方式&#xff0c;让你的测试用例能够以随机顺序执行。本文将深入介绍 pytest-random-order 插件的基本用法和实际案例&#xff0c;助你摆脱固定的测…

ICCV2023 | MCD: Misalign, Contrast then Distill:重新思考VLP中的错位

论文标题: Misalign, Contrast then Distill: Rethinking Misalignments in Language-Image Pretraining 论文地址&#xff1a;ICCV 2023 Open Access Repository 代码&#xff1a;None LG AI Research 一、问题提出 SLIP发现&#xff0c;在CLIP中引入增强&#xff08;特别…

spring项目aop实现接口防止连续点击锁

aop实现 1&#xff0c;注解 注解用于接口方法、接口参数、和请求实体的属性上。 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** author dll*/ Ta…

MfgTool烧写工具

系列文章目录 MfgTool烧写工具 MfgTool烧写工具 系列文章目录一、MfgTool工具简介二、烧写NXP官方系统三、烧写自己的系统四、改造自己的烧写工具 一、MfgTool工具简介 1、mfgtool是NXP官方做的向I.MX系列烧写系统的软件&#xff0c;运行在windows下。可以烧写uboot.imx、zIma…

如何在Shopee深圳站点进行选品并提高销售潜力?

在如今的电商市场中&#xff0c;选品是卖家们提高销售业绩的重要环节。对于在Shopee深圳站点进行选品的卖家来说&#xff0c;了解市场需求、分析竞争对手、优化供应链管理、制定合理的价格策略以及精准的营销策略都是至关重要的。本文将为您介绍一些关键策略&#xff0c;帮助您…

php目录操作示例

目录 1.常用函数 2.列举当前目录列表 3.判断是否是文件夹 1.常用函数 函数名功能scandir 列出指定路径中的文件和目录 opendir 打开文件夹&#xff0c;返回操作资源 readdir读取文件夹资源closedir 关闭文件夹操作资源 is_dir 判断是否是文件夹 filetype 显示是文件夹还是文…

CSS 蜡烛效果

<template><view class="holder"><!-- 身子 --><view class="candle"><!-- 光源 --><view class="blinking-glow"></view><!-- 火星子 --><view class="thread"></view>…

transformer优化(二)-DETR 学习笔记

论文地址&#xff1a;https://arxiv.org/pdf/2005.12872.pdf 代码地址&#xff1a;https://github.com/bubbliiiing/detr-pytorch https://github.com/facebookresearch/detr 1.是什么&#xff1f; DETR&#xff08;Detection Transformer&#xff09;是一种基于Transforme…

新崛起的自动化神器Playwright

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

词语的魔力:语言在我们生活中的艺术与影响

Words That Move Mountains: The Art and Impact of Language in Our Lives 词语的魔力&#xff1a;语言在我们生活中的艺术与影响 Hello there, wonderful people! Today, I’d like to gab about the magical essence of language that’s more than just a chatty tool in o…

怎么去除水中的溴酸盐

语&#xff1a;近年来&#xff0c;我国矿泉水市场发展迅速&#xff0c;各种品牌和类型的矿泉水琳琅满目。然而&#xff0c;在众多矿泉水产品中&#xff0c;部分产品却存在溴酸盐超标的问题。本文将为您揭示矿泉水溴酸盐超标的危害&#xff0c;提醒消费者在选购矿泉水时务必谨慎…

redis的事件机制

文章目录 文件事件1. 文件事件处理器的构成2. I/O多路复用程序的实现3. 事件的类型4. 文件事件的处理器 时间事件1. 实现 事件的调度与执行 Redis服务器是一个事件驱动程序&#xff08;单Reactor单线程模型&#xff09;&#xff0c;服务器需要处理以下两类事件&#xff1a; 文件…

Kafka(三)【Broker 存储】

目录 前言 Kafka Broker 1、工作流程 1.1、Zookeeper 存储的 Kafka 信息 1.2、Kafka Broker 的总体工作流程 1.3、Broke 重要参数 2、Kafka 副本 2.1、副本基本信息 2.2、Keader 选举流程 2.3、Leader 和 Follower 的故障处理细节 Follower 故障 Leader 故障&#x…

2017年认证杯SPSSPRO杯数学建模A题(第一阶段)安全的后视镜全过程文档及程序

2017年认证杯SPSSPRO杯数学建模 A题 安全的后视镜 原题再现&#xff1a; 汽车后视镜的视野对行车安全非常重要。一般来说&#xff0c;汽车的后视镜需要有良好的视野范围&#xff0c;以便驾驶员能够全面地了解车后方的道路情况。同时&#xff0c;后视镜也要使图像的畸变尽可能…

国产品牌GC6609与TM2209的参数分析,为什么适用于3D打印机,医疗器械等产品中

步进电机驱动的应用方案目前市场上大多选用国外品牌的电机驱动器&#xff0c;其中trinamic的TMC2208/2209在这一块的应用很广泛。但是由于市场越来越应激。&#xff0c;当前对于产品开发成本要求也越来越低&#xff0c;国产品地准出了相应的TMC2208/2209&#xff0c;因此trinam…

Vue3+ElementUI 多选框中复选框和名字点击方法效果分离

现在的需求为 比如我点击了Option A &#xff0c;触发点击Option A的方法&#xff0c;并且复选框不会取消勾选&#xff0c;分离的方法。 <el-checkbox-group v-model"mapWork.model_checkArray.value"> <div class"naipTypeDom" v-for"item …

国家急救日倡议活动暨120急救大课堂公益培训在京成功举办

2024年1月20日&#xff0c;由国家卫生健康委员会等多个相关部门指导&#xff0c;中国医院协会急救中心&#xff08;站&#xff09;分会主办&#xff0c;北京急救中心承办的“国家急救日”倡议活动暨急救科普大课堂公益培训系列活动&#xff0c;在全国范围内启动。 健康中国行动…

王晶感慨62岁刘德华的一日三餐,简直不是人过的日子

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 你是否曾对那些身材保持得如此之好的人感到过羡慕&#xff1f…

使用vue-pdf插件加载pdf

安装&#xff1a; // 安装这个版本&#xff0c;其它版本会有千奇百怪的错&#xff0c;这个版本和4.0.0都是可以的 cnpm install vue-pdf4.2.0// 安装pdfjs-dist cnpm install pdfjs-dist2.5.207 使用&#xff1a; // 我的css样式是pxToRem&#xff0c;友友们使用可能样式会有…

HCIP之BGP联邦实验

华子目录 实验拓扑及要求规划网段和IP地址实验步骤配置IP地址先让IGP通建BGP邻居修改ospf下环回接口网络类型修改联邦之间的最大跳数每台运行BGP的路由器批量宣告路由修改本地下一跳测试 实验拓扑及要求 规划网段和IP地址 实验步骤 配置IP地址 r1配置&#xff0c;依次类推 […