【数据结构】哈希桶

目录

前言:

开散列(哈希桶)

开散列的概念

哈希桶的模拟实现

 整体框架

查找

插入

删除

析构函数


前言:

闭散列线性探测缺点:一旦发生哈希冲突,所有的产生哈希冲突的数据连续存储在一块区域,容易产生数据"堆积",即:不同关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致搜索效率降低,并且闭散列导致空间利用率低,因此本文探索采用开散列(哈希桶)的数据结构从而避免数据 "堆积" ;

开散列(哈希桶)

开散列的概念

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

接起来,各链表的头结点存储在哈希表中;

哈希桶的模拟实现

 整体框架

template<class K, class V>
struct HashNode
{HashNode<K, V>* _next;pair<K, V> _kv;//开辟结点时需要结点的构造函数HashNode(const pair<K, V>& kv){_kv = kv;_next = nullptr;}
};template<class K, class V>
class HashTable
{typedef HashNode<K, V> Node;
public://...
private:vector<Node*> _tables;size_t _n;//记录哈希表中实际存放的数据个数
};

查找

思路:

首先根据键值key使用哈希函数计算哈希地址,确定待查找的数据的位置;

其次遍历桶中数据,查找到返回数据所在结点的指针,查找不到返回空指针;

Node* Find(const K& key)
{size_t hashi = key % _tables.size();Node* cur = _tables[hashi];while (cur != nullptr){if ((cur->_kv).first == key){return cur;}cur = cur->_next;}return nullptr;
}

插入

开散列最优情形:每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数时,考虑哈希表扩容

  • 查看哈希表中是否存在该键值的键值对,若已存在则插入失败;
  • 当负载因子增加到1时,进行扩容操作(即创建一个新的哈希表,该哈希表的大小为原哈希表的两倍,然后遍历原哈希表,将原哈希表中的结点插入到新哈希表,最后将原哈希表与新哈希表交换即可);
  • 将结点插入哈希桶(头插);
  • 哈希表中的记录实际存储的数据个数自增1;
//构造函数
HashTable(size_t n = 10)
{_tables.resize(n, nullptr);_n = 0;
}
bool Insert(const pair<K, V>& kv)
{//若键值对中的键值key已存在,则插入失败Node* ret = Find(kv.first);if (ret != nullptr){return false;}//控制负载因子为1,即哈希表中实际存放的数据个数与哈希表长度长度相等if (_n == _tables.size()){//新表扩容到旧表的两倍vector<Node*> _newtables(_tables.size() * 2);//遍历旧表,取旧表结点头插到新表for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur != nullptr){Node* nextnode = cur->_next;size_t hashi = cur->_kv.first % _newtables.size();cur->_next = _newtables[hashi];_newtables[hashi] = cur;cur = nextnode;}_tables[i] = nullptr;}//交换新表与旧表_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;
}

删除

bool Erase(const K& key)
{//确定待删除数据的位置size_t hashi = key % _tables.size();Node* cur = _tables[hashi];Node* prev = nullptr;while (cur != nullptr){if ((cur->_kv).first == key){//删除if (prev != nullptr){prev->_next = cur->_next;}else{_tables[hashi] = cur->_next;}delete cur;--_n;return true;}else{prev = cur;cur = cur->_next;}}return false;
}

析构函数

//析构函数
~HashTable()
{for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur != nullptr){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}
}

当哈希表中的HashNode存储string时,string类型的数据不支持取模运算,若采用运算符重载,需要更改库中的string,除留余数法如何建立string类型数据与存储位置的映射关系吗?

解决方案:

  1. 首先将string类型转换为整型,建立string类型与整型的映射关系(采用仿函数实现);
  2. 其次转换后的整型值与存储位置建立映射关系(模版参数增加1个接收仿函数);

思考:任意类型的值如何转换为整型值 ?

  • 本身为整型家族的成员,则可以通过强制类型转换可以转化为整型;
  • 对于string类型,可以取每个字符的ASCII码值,逐个相加且每相加一次乘以权重31;
  • 对于其他类型,按数据类型各自的特征自定义仿函数实现转换为整型;
template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};//string类型使用模版的特化
template<>
struct HashFunc<string>
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){hash += e;hash *= 31;//BKDR字符串哈希算法,累乘因子为31}return hash;}
};
template<class K, class V, class Hash = HashFunc<K>>
class HashTable
{typedef HashNode<K, V> Node;
public://...
private:vector<Node*> _tables;size_t _n;//记录哈希表中实际存放的数据个数
};

欢迎大家批评指正,博主会持续输出优质内容,谢谢各位观众老爷观看,码字画图不易,希望大家给个一键三连支持~ 你的支持是我创作的不竭动力~

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

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

相关文章

ios微信小程序禁用下拉上拉

第一步&#xff1a; page.json配置页面的"navigationStyle":"custom"属性&#xff0c;禁止页面滑动 "navigationStyle":"custom" 第二步&#xff1a; 页面里面使用scroll-view包裹内容&#xff0c;内容可以内部滑动 <view class&…

Oracle中rman使用记录

最近在项目中&#xff0c;遇到使用RMAN的操作来恢复数据库中某个时间归档日志&#xff0c;RMAN的原理和理解&#xff0c;网友们百度了解一下。我重点将实操部分了。直接上实验环节&#xff0c;让网友更懂。&#xff08;特别提醒&#xff1a;我是1:1用VMware克隆数据库进行RMAN还…

如何看待AIGC技术

目录 1.概述 2.技术应用 2.1.媒体与内容创作 2.2.教育与学习 ​​​​​​​2.3.艺术创作 ​​​​​​​2.4.游戏产业 ​​​​​​​2.5.工业设计 ​​​​​​​2.6.对未来社会的影响 2.7.可能的发展方向 ​​​​​​​2.8.小结 3.伦理与风险 3.1.AIGC技术面临…

零基础HTML教程(26)--表单元素标注

文章目录 1. 引子2. 使用标注3. 元素的id与name4. 更好的写法5. 小结 1. 引子 我们看一个表单&#xff1a; <form>姓名&#xff1a;<input type"text"><br>手机号:<input type"text"><br>年龄:<input type"text&qu…

MES管理系统工单管理模块的重要性

在现代制造企业中&#xff0c;MES管理系统作为生产流程管理的核心&#xff0c;工单模块则扮演着不可或缺的角色。它不仅是MES管理系统的基石&#xff0c;更是连接各个生产环节的纽带&#xff0c;确保生产流程的顺畅与高效。 首先&#xff0c;我们需要明确MES管理系统在制造企业…

深度解析 Spring 源码:揭秘BeanFactory 之谜

文章目录 一、认识BeanFactory1.1 BeanFactory的概述1.2 BeanFactory与 ApplicationContext的区别 二、BeanFactory源码解读2.1 BeanFactory 接口2.1.1 getBean()2.1.2 containsBean()2.1.3 isSingleton() 2.2 DefaultListableBeanFactory 类2.2.1 registerBeanDefinition()2.2…

南宁建筑模板供应商:贵港市能强优品木业有限公司

贵港市能强优品木业有限公司&#xff0c;作为南宁地区知名的建筑模板生产厂家&#xff0c;拥有25年的丰富生产经验。该公司生产的建筑覆膜板以其稳定的质量和高周转次数而闻名&#xff0c;多年来参与了国内各地区众多大型建筑项目&#xff0c;并获得广大客户的一致好评。 质量稳…

Object类 equals方法 hashCode方法 集合

Object类 Object类是所有类的父类&#xff0c;所以&#xff1a; Object的类的成员变量和成员方法&#xff0c;其余的类会继承&#xff0c;可以使用 Object类可以使用多态创建任意对象&#xff0c;同时拥有子类的重写方法 我们先假设子类重写了equals方法和hashCode方法&…

Flink 实时数仓(一)【实时数仓离线数仓对比】

前言 昨天技术面的时候&#xff0c;面试官说人家公司现在用的都是最新的技术&#xff0c;比如 Doris 等一些最新的工具&#xff0c;确实这些课是学校永远不会开设的&#xff0c;好在他说去了会带着我做一做。可是 ...... 学院舍不得让走啊 ...... 没办法&#xff0c;情况就是这…

python代码报错requests.exceptions.SSLError

直接浏览器访问报ssl错误的网站&#xff0c;然后找到证书&#xff0c;选择导出 然后在cmd里面执行&#xff0c;去查看certifi的位置 python -c "import certifi;print(certifi.where())"找到之后用文本编辑器打开&#xff0c;我用的vscode 滚动到最后面&#xff0c…

什么是重放攻击(Reply attack)?

什么是重放攻击(Reply attack)? 重放攻击&#xff0c;也称为回放攻击&#xff0c;是一种网络攻击方式。重放攻击是一种中间人攻击&#xff0c;攻击者通过截获合法的数据传输并重新发送它们来欺骗接收方&#xff0c;让接收方误以为是合法的消息。重放攻击是非常常见的&#xf…

在IDEA中使用.env文件导入系统配置的图文教程

JetBrains的IDEA是一款功能强大的集成开发环境&#xff0c;为开发人员提供了丰富的功能和工具。使用.env文件来管理配置信息在IDEA中非常简单。 旧版本默认支持&#xff0c;新版本idea需要安装插件才可以。 这里我们可以安装EnvFile插件&#xff0c;步骤如下&#xff1a; 在弹…

详解数仓的向量化执行引擎

前言 适用版本&#xff1a;【基线功能】 传统的行执行引擎大多采用一次一元组的执行模式&#xff0c;这样在执行过程中CPU大部分时间并没有用来处理数据&#xff0c;更多的是在遍历执行树&#xff0c;就会导致CPU的有效利用率较低。而在面对OLAP场景巨量的函数调用次数&#x…

ctfshow web29-web40

命令执行 看清都过滤了些什么&#xff01;&#xff01; 知识点&#xff1a; web34&#xff1a;当;和()被过滤了就用语言结构&#xff0c;一般有echo print isset unset include require web37&#xff1a;data协议是将后面的字符串当成php代码执行&#xff0c;例如 /?cdat…

JVM学习笔记(四)类加载与字节码技术

目录 一、类文件结构 二、字节码指令 2.3 图解方法执行流程 1&#xff09;原始 java 代码 2&#xff09;编译后的字节码文件 3&#xff09;常量池载入运行时常量池 4&#xff09;方法字节码载入方法区 5&#xff09;main 线程开始运行&#xff0c;分配栈帧内存 6&…

甘特图是什么?如何利用其优化项目管理流程?

甘特图是项目管理软件中十分常见的功能&#xff0c;可以说每一个项目经理都要学会使用甘特图才能更好的交付项目。什么是甘特图&#xff1f;甘特图用来做什么&#xff1f;简单来说一种将项目任务与时间关系直观表示的图表&#xff0c;直观地展示了任务进度和持续时间。 一、甘特…

【C++】string类的增删改查模拟实现(图例超详细解析!!!)

目录 一、前言 二、string类的模拟实现 ✨前情提要 ✨Member functions —— 成员函数 ⚡构造函数 ⚡拷贝构造函数 ⚡赋值运算符重载 ⚡析构函数 ✨Element access —— 元素访问 ⚡operator[ ] ⚡Iterator —— 迭代器 ✨Capacity —— 容量 ⚡size ⚡capacity ⚡clea…

井字棋源码(网络线程池版)

源码链接&#xff1a;game 效果可能没有那么好&#xff0c;大家可以给点建议。 效果展示 game.h #include <stdio.h> #include <stdlib.h> #include <time.h>#define ROW 3 #define COL 3void InitBoard(char board[ROW][COL], int row, int col) {int i…

企业数字化转型,“业务”先行

在当今时代&#xff0c;数字化转型已经成为企业发展的必经之路。数字化转型&#xff0c;简而言之&#xff0c;就是运用数字技术&#xff0c;对企业运营管理的各个环节进行深度改造&#xff0c;以提升企业的运营效率和市场竞争力。据有关机构研究测算&#xff0c;数字化转型可使…

丈母娘眼中“靠谱女婿”职业榜曝光,公务员跌落榜首,新兴职业成宠儿!

正如婆婆和媳妇相处很复杂&#xff0c;丈母娘和女婿亦有着微妙关系&#xff0c;看对眼是“半个儿”&#xff0c;不对付则会成为小两口婚姻的“地雷”&#xff0c;甚至是恋爱路上的“拦路虎”。 近来&#xff0c;最新丈母娘认可的“靠谱女婿”职业榜排行新鲜出炉&#xff0c;备受…