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

数据结构——哈希详解

数据结构——哈希详解

目录

一、哈希的定义

二、六种哈希函数的构造方法

2.1 除留取余法

2.2 平方取中法

2.3 随机数法

2.4 折叠法

2.5 数字分析法

2.6 直接定值法

三、四种解决哈希冲突的方法

3.1 开放地址法

3.1.1 线性探测法

3.1.2 二次探测法

3.2 链地址法

3.3 再散列函数法

3.4 公共区溢出法

四、用代码解决链地址法


一、哈希的定义

顺序表/链表有一个共同特征,数据值本身和其存储位置之间是没有关系的,所以我们要查找/搜索一个值,只能一个一个的去比较,时间复杂度是O(n),

我们想把时间复杂度降下来,提供一种技术让我们数据值本身和存储关系之前有映射关系,这时我们查找值是否存在则直接根据这种映射关系计算得出其存储位置,这时只去要去计算得出的存储位置查看即可——这种技术就是散列技术也就是哈希,映射关系就是哈希函数f   

f(关键字key)=存储位置

哈希即是一种存储方法也是一种查找方法

哈希冲突定义:俩个或多个关键码Key1!=Key2但是通过哈希函数的计算得出的结果却相等,这种现象就是发生了哈希冲突

二、六种哈希函数的构造方法

2.1 除留取余法

原理

  • 哈希函数 h(k)=k mod m,其中 k 是键值,m 是哈希表的大小。

  • 通过取键值 k 除以 m 的余数来确定哈希值。

优点

  • 实现简单,计算速度快。

缺点

  • 如果键值分布不均匀,容易导致冲突。例如,当键值都是偶数时,若 m 是偶数,那么所有哈希值也都是偶数,会浪费一半的哈希表空间。

  • 对 m 的选择敏感,通常 m 选择为质数可以减少冲突。

应用场景

  • 适用于键值范围较大且分布较为均匀的场景,如简单的哈希表设计。

2.2 平方取中法

原理

  • 将键值 k 平方,然后从平方后的结果中取出中间几位数字作为哈希值。

  • 例如,键值 k=1234,平方后为 1522756,取中间几位(如 2275)作为哈希值。

优点

  • 能够较好地打乱键值的分布,减少冲突。

缺点

  • 如果键值较小,平方后的数字位数不够,可能需要补零,导致哈希值不够随机。

  • 计算平方操作相对耗时。

应用场景

  • 适用于对哈希值随机性要求较高的场景,但计算资源允许的情况下。

2.3 随机数法

原理

  • 使用伪随机数生成器(PRNG)根据键值生成随机数作为哈希值。

  • 通常需要一个种子值,种子值可以根据键值计算得到。

优点

  • 哈希值的随机性高,冲突概率低。

缺点

  • 随机数生成器的实现复杂,且需要保证每次计算结果一致(即相同的键值产生相同的哈希值)。

  • 如果随机数生成器质量不高,可能会导致哈希值分布不均匀。

应用场景

  • 适用于对哈希值随机性要求极高的场景,如密码学中的哈希函数。

2.4 折叠法

原理

  • 将键值分成若干部分,然后将这些部分进行折叠(相加、相减或按位运算)以生成哈希值。

  • 例如,键值 k=12345678,可以分成 1234 和 5678,然后相加得到 6912,再取模或者直接取后三位得到最终哈希值。

优点

  • 简单易实现,能够较好地处理较长的键值。

缺点

  • 如果键值的某些部分分布不均匀,可能会影响哈希值的分布。

  • 对折叠操作的选择敏感,不同的折叠方式可能导致不同的效果。

应用场景

  • 适用于键值较长且分布不均匀的场景,如字符串哈希。

2.5 数字分析法

原理

  • 分析键值的每一位数字(或字符),根据某种规则选择部分数字组合成哈希值。

  • 例如,键值 k=12345678,可以选择第 2、4、6 位数字(2、4、6),然后组合成 246 作为哈希值。

优点

  • 能够根据键值的分布特点进行优化,减少冲突。

缺点

  • 实现复杂,需要对键值的分布有先验知识。

  • 如果键值的分布变化较大,可能需要重新调整规则。

应用场景

  • 适用于对键值分布有明确了解的场景,如特定的数据库索引设计。

2.6 直接定值法

原理

  • 取关键字的线性函数值作为散列地址 f(key)=axkey+b 

  • 通常用于键值范围较小且连续的情况。

优点

  • 实现极其简单,没有冲突。

缺点

  • 如果键值范围较大,会浪费大量空间。

  • 不适用于键值范围较大的场景。

应用场景

  • 适用于键值范围较小且连续的场景,如小型数据库索引。

三、四种解决哈希冲突的方法

哈希冲突定义:俩个或多个关键码Key1!=Key2但是通过哈希函数的计算得出的结果却相等,这种现象就是发生了哈希冲突

3.1 开放地址法

3.1.1 线性探测法

原理:当发生哈希冲突时,从冲突位置开始,按照线性顺序依次探测下一个位置,向右探测,直到找到空闲位置为止。即若哈希地址为 h(key) 的位置已被占用,则依次探测 h(key)+1、h(key)+2、h(key)+3…… 直到找到空闲位置。

优点:实现简单,容易理解和编程实现。

缺点:容易出现 “聚集” 现象,即连续的多个空闲位置被占用,形成一个聚集区,导致后续元素查找和插入时需要探测更多的位置,效率降低。

公式:f(key)=(f(key)+d)mod m      d=1,2,3,4,5…

3.1.2 二次探测法

使用线性探测法会发生堆积,我们想要探测的时候即向左也向右探测并且每次探测幅度尽可能变化,呈指数变化 eg:1,-1,4,-4,9,-9

增加平方运算是为了不让关键字都聚集在某一个区域

优点:能有效减少聚集现象,提高哈希表的性能。

缺点:不能探测到哈希表中的所有位置,可能会出现无法找到空闲位置的情况,特别是当哈希表大小不是合适的数值时。

3.2 链地址法

其核心思想是将所有哈希地址相同的元素都链接到同一个链表中。在哈希表中,每个位置对应一个链表,当发生哈希冲突(即不同的关键字通过哈希函数计算得到相同的哈希地址)时,将这些冲突的元素依次插入到对应的链表中

优点

  • 处理冲突简单,不需要探测。

  • 删除元素容易,只需从链表中移除即可。

缺点

  • 需要额外的空间来存储链表。

  • 当一个槽位的链表很长时,搜索效率会降低。

3.3 再散列函数法

再散列函数法使用两个不同的哈希函数。第一个哈希函数 h1(key) 用于计算元素的初始哈希地址。当该地址发生冲突时,使用第二个哈希函数 h2(key) 来确定下一个探测位置的步长,从而在哈希表中寻找下一个可用的位置。

通过这种方式,不断尝试新的位置,直到找到一个空槽来插入元素,或者确定该元素不存在于哈希表中。

3.4 公共区溢出法

不冲突放到基本表中,冲突就放到溢出表中,基本表中都没有数据为空说明溢出表中肯定没有,基本表由哈希函数构成,溢出表由顺序存储构成先来先到,

适用于哈希冲突相对较少的场景

四、用代码解决链地址法

.cpp

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "hash_List_address.h"
#include <stdlib.h>//0.哈希函数
int Hash(ELEM_TYPE val)
{return val % INITSIZE;
}//1.初始化
void Init_List_Address(List_address* pla)
{for (int i = 0; i < INITSIZE; i++){Init_List(&pla->arr[i]);}
}//2.插入值(头插)
bool Insert(List_address* pla, ELEM_TYPE val)
{//assertint index = Hash(val);struct Node* pnewnode = (Node*)malloc(sizeof(Node));if (pnewnode == NULL){return false;}pnewnode->data = val;pnewnode->next = pla->arr[index].next;pla->arr[index].next = pnewnode;return true;
}//3.删除值
bool Del(List_address* pla, ELEM_TYPE val)
{struct Node* q = Search(pla, val);if (q == NULL)return false;//此时,代码执行到这里,证明val值节点存在在index下标里面的单链表上int index = Hash(val);struct Node* p = &pla->arr[index];for (; p->next != q; p = p->next);//此时,代码执行到这里,证明p和q都就位p->next = q->next;free(q);q = NULL;return true;
}//4.查找值
struct Node* Search(List_address* pla, ELEM_TYPE val)
{//assertint index = Hash(val);struct Node* q = pla->arr[index].next;for (; q != NULL; q = q->next){if (q->data == val){break;}}return q;}//5.打印
void Show(List_address* pla)
{for (int i = 0; i < INITSIZE; i++){printf("第%d行:", i);struct Node* p = pla->arr[i].next;for (; p != NULL; p=p->next){printf("%d->", p->data);}printf("\n");}
}int main()
{List_address head;Init_List_Address(&head);Insert(&head, 12);Insert(&head, 67);Insert(&head, 56);Insert(&head, 16);Insert(&head, 25);Insert(&head, 37);Insert(&head, 22);Insert(&head, 29);Insert(&head, 15);Insert(&head, 47);Insert(&head, 48);Insert(&head, 34);Show(&head);Del(&head, 25);Del(&head, 12345);Show(&head);return 0;
}

.h 

#pragma oncetypedef int ELEM_TYPE;
//链地址法有效节点结构体设计:
typedef struct List_Node
{ELEM_TYPE data;struct List_Node* next;
}List_Node;#include "list.h"//链地址法整个的辅助节点结构体设计:
#define INITSIZE 12
typedef struct List_address
{struct Node arr[INITSIZE];
}List_address;//0.哈希函数
int Hash(ELEM_TYPE val);//1.初始化
void Init_List_Address(List_address* pla);//2.插入值
bool Insert(List_address* pla, ELEM_TYPE val);//3.删除值
bool Del(List_address* pla, ELEM_TYPE val);//4.查找值
struct Node* Search(List_address* pla, ELEM_TYPE val);//5.打印
void Show(List_address* pla);

相关文章:

数据结构——哈希详解

数据结构——哈希详解 目录 一、哈希的定义 二、六种哈希函数的构造方法 2.1 除留取余法 2.2 平方取中法 2.3 随机数法 2.4 折叠法 2.5 数字分析法 2.6 直接定值法 三、四种解决哈希冲突的方法 3.1 开放地址法 3.1.1 线性探测法 3.1.2 二次探测法 3.2 链地址法 3…...

Spark-SQL核心编程

简介 Hadoop与Spark-SQL的对比 Hadoop在处理结构化数据方面存在局限性&#xff0c;无法有效处理某些类型的数据。 Spark应运而生&#xff0c;特别设计了处理结构化数据的模块&#xff0c;称为Spark SQL&#xff08;原称Shark&#xff09;。 SparkSQL的发展历程&#xff1a; Sp…...

pywebview 常用问题分享

文章目录 前言问题描述与方案(待补充)1、动态设置本地调试目录和打包目录2、构建后运行程序白屏 前言 最近做一个pywebview项目&#xff0c;遇到了一些问题&#xff0c;记录一下&#xff0c;分享给大家&#xff0c;希望能帮助有遇到相似问题的人事。 问题描述与方案(待补充) …...

系统设计模块之安全架构设计(身份认证与授权(OAuth2.0、JWT、RBAC/ABAC))

一、OAuth 2.0&#xff1a;开放授权框架 OAuth 2.0 是一种标准化的授权协议&#xff0c;允许第三方应用在用户授权下访问其资源&#xff0c;而无需直接暴露用户密码。其核心目标是 分离身份验证与授权&#xff0c;提升安全性与灵活性。 1. 核心概念与流程 角色划分&#xff…...

Docker 与 Podman常用知识汇总

一、常用命令的对比汇总 1、基础说明 Docker&#xff1a;传统的容器引擎&#xff0c;使用 dockerd 守护进程。 Podman&#xff1a;无守护进程、无root容器引擎&#xff0c;兼容 Docker CLI。 Podman 命令几乎完全兼容 Docker 命令&#xff0c;只需将 docker 替换为 podman。…...

如何通过自动化解决方案提升企业运营效率?

引言 在现代企业中&#xff0c;运营效率直接影响着企业的成本、速度与竞争力。尤其是随着科技的不断发展&#xff0c;传统手工操作和低效的流程逐渐无法满足企业的需求。自动化解决方案正成为企业提升运营效率、降低成本和提高生产力的关键。无论是大型跨国公司&#xff0c;还…...

unity100天学习计划

以下是一个为期100天的Unity学习大纲,涵盖从零基础到独立开发完整游戏的全流程,结合理论、实践和项目实战,每天学习2-3小时: 第一阶段:基础奠基(Day 1-20) 目标:掌握Unity引擎基础与C#编程 Day 1-5:引擎入门 安装Unity Hub和Unity Editor(LTS版本)熟悉Unity界面:S…...

多坐标系变换全解析:从相机到WGS-84的空间坐标系详解

多坐标系变换全解析:从相机到WGS-84的空间坐标系详解 一、常见坐标系简介二、各坐标系的功能和使用场景1. WGS-84 大地坐标系(经纬高)2. 地心直角坐标系(ECEF)3. 本地 ENU / NED 坐标系4. 平台坐标系(Body)5. 相机坐标系三、坐标变换流程图四、如何选用合适的坐标系?五…...

SpringCloud Alibaba 之分布式全局事务 Seata 原理分析

1. 什么是 Seata&#xff1f;为什么需要它&#xff1f; 想象一下&#xff0c;你去银行转账&#xff1a; 操作1&#xff1a;从你的账户扣款 1000 元操作2&#xff1a;向对方账户增加 1000 元 如果 操作1 成功&#xff0c;但 操作2 失败了&#xff0c;你的钱就凭空消失了&…...

作业帮前端面试题及参考答案 (100道面试题-上)

HTML5 的优势是什么? HTML5 作为 HTML 语言的新一代标准,具有众多显著优势,为现代网页开发带来了诸多便利与革新。 在语义化方面,HTML5 引入了大量具有明确语义的标签,如<header>、<nav>、<article>、<section>、<aside>、<footer>等…...

Large Language Model(LLM)的训练和微调

之前一个偏工程向的论文中了&#xff0c;但是当时对工程理论其实不算很了解&#xff0c;就来了解一下 工程流程 横轴叫智能追寻 竖轴上下文优化 Prompt不行的情况下加shot(提示)&#xff0c;如果每次都要加提示&#xff0c;就可以试试知识库增强检索来给提示。 如果希望增强…...

统计销量前十的订单

传入参数&#xff1a; 传入begin和end两个时间 返回参数 返回nameList和numberList两个String类型的列表 controller层 GetMapping("/top10")public Result<SalesTop10ReportVO> top10(DateTimeFormat(pattern "yyyy-MM-dd") LocalDate begin,Dat…...

AI大模型原理可视化工具:深入浅出理解大语言模型的工作原理

AI大模型原理可视化工具&#xff1a;深入浅出理解大语言模型的工作原理 在人工智能快速发展的今天&#xff0c;大语言模型&#xff08;如GPT、BERT等&#xff09;已经成为改变世界的重要技术。但对于很多人来说&#xff0c;理解这些模型的工作原理仍然是一个挑战。为了帮助更多…...

MCP 认证考试常见技术难题实战分析与解决方案

MCP(Microsoft Certified Professional)认证考试在全球范围内被广泛认可,是衡量个人在微软技术领域专业能力的重要标准。然而,在备考和参加 MCP 认证考试过程中,考生常常会遇到各种技术难题。以下将对一些常见技术难题进行实战分析,并提供相应的解决方案。​ 一、网络配…...

qt designer 创建窗体选择哪种屏幕大小

1. 新建窗体时选择QVGA还是VGA 下面这个图展示了区别 这里我还是选择默认&#xff0c;因为没有特殊需求&#xff0c;只是在PC端使用...

Spark-SQL核心编程(一)

一、Spark-SQL 基础概念 1.定义与起源&#xff1a;Spark SQL 是 Spark 用于结构化数据处理的模块&#xff0c;前身是 Shark。Shark 基于 Hive 开发&#xff0c;提升了 SQL-on-Hadoop 的性能&#xff0c;但因对 Hive 依赖过多限制了 Spark 发展&#xff0c;后被 SparkSQL 取代&…...

Android WiFi获取动态IP地址

Android开发中获取WiFi动态IP地址可通过以下方法实现&#xff0c;需结合网络状态管理和API调用&#xff1a; 一、权限配置 在AndroidManifest.xml中添加必要权限&#xff1a; <uses-permission android:name"android.permission.ACCESS_WIFI_STATE" /> <…...

正则表达式使用知识(日常翻阅)

正则表达式使用 一、字符匹配 1. 普通字符 描述&#xff1a;直接匹配字符本身。示例&#xff1a; abc 匹配字符串中的 “abc”。Hello 匹配字符串中的 “Hello”。 2. 特殊字符 .&#xff08;点号&#xff09;&#xff1a; 描述&#xff1a;匹配任意单个字符&#xff08;…...

AI与无人驾驶汽车:如何通过机器学习提升自动驾驶系统的安全性?

引言 想象一下&#xff0c;在高速公路上&#xff0c;一辆无人驾驶汽车正平稳行驶。突然&#xff0c;前方的车辆紧急刹车&#xff0c;而旁边车道有一辆摩托车正快速接近。在这千钧一发的瞬间&#xff0c;自动驾驶系统迅速分析路况&#xff0c;判断最安全的避险方案&#xff0c;精…...

第5篇:Linux程序访问控制FPGA端LEDR<三>

Q&#xff1a;如何具体设计.c程序代码访问控制FPGA端外设&#xff1f; A&#xff1a;以控制DE1-SoC开发板的LEDR为例的Linux .C程序代码。头文件fcntl.h和sys/mman.h用于使用/dev/mem文件&#xff0c;以及mmap和munmap内核函数&#xff1b;address_map_arm.h指定了DE1-SoC_Com…...

城市应急安防系统EasyCVR视频融合平台:如何实现多源视频资源高效汇聚与应急指挥协同

一、方案背景 1&#xff09;项目背景 在当今数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;视频监控和应急指挥系统在公共安全、城市应急等领域的重要性日益凸显。尤其是在关键场所&#xff0c;高效的视频资源整合与传输能力对于应对突发公共事件、实现快速精准的…...

主流程序员接单平台的分类整理与分析

一、主流推荐平台 1.程序员客栈 特点&#xff1a;国内知名度高&#xff0c;需求池模式自动匹配项目&#xff0c;项目经理介入协调争议&#xff0c;流程规范。 优势&#xff1a;适合新手到资深开发者&#xff0c;资金托管安全性高&#xff0c;交易纠纷处理专业。 不足&…...

【笔记ing】AI大模型-03深度学习基础理论

神经网络&#xff1a;A neural network is a network or circuit of neurons,or in a modern sense,an artificial neural network,composed of artificial neurons or nodes.神经网络是神经元的网络或回路&#xff0c;或者在现在意义上来说&#xff0c;是一个由人工神经元或节…...

Hutool工具包中`copyProperties`和`toBean`的区别

前言 在Java开发中&#xff0c;对象转换是一项常见且重要的操作。Hutool作为一个功能强大的Java工具包&#xff0c;提供了copyProperties和toBean这两个实用的方法来帮助我们进行对象转换。然而&#xff0c;很多开发者对这两个方法的区别和使用场景并不十分清楚。 一、Hutool…...

高德地图 JS-SDK 实现教程

高德地图 JS-SDK 实现教程&#xff1a;定位、地图选点、地址解析等 适用地点选择、地址显示、表单填写等场景&#xff0c;全面支持移动端、手机浏览器和 PC端环境 一、创建应用&Key 前端&#xff08;JS-SDK、地图组件&#xff09; 登陆 高德开放平台创建应用&#xff0c;…...

07软件测试需求分析案例-修改用户信息

修改用户信息是后台管理菜单的一个功能模块&#xff0c;只有admin才有修改权限。包括查询用户名进行显示用户相关信息&#xff0c;并且修改用户相关信息的功能。 1.1 通读文档 通读需求规格说明书是提取信息&#xff0c;提出问题&#xff0c;输出具有逻辑、规则、流程的业务…...

分层对象模型:PO、DTO、VO、BO定义区别与使用场景

目录 前言 PO&#xff08;持久化对象&#xff09; DTO&#xff08;数据传输对象&#xff09; VO&#xff08;视图对象&#xff09; BO&#xff08;业务对象&#xff09; 关键区别总结 典型应用场景 为什么要分层设计 工具支持 前言 在开发中&#xff0c;我们经常遇到…...

设计模式 --- 状态模式

状态模式​​是一种​​行为型设计模式​​&#xff0c;允许对象在内部状态改变时动态改变其行为​​&#xff0c;使对象的行为看起来像是改变了。该模式通过将状态逻辑拆分为独立类​​&#xff0c;消除复杂的条件分支语句&#xff0c;提升代码的可维护性和扩展性。 状态模式的…...

Java多态课堂练习题

Java多态课堂练习题 题目&#xff1a;动物乐园的多态展示 背景设定&#xff1a; 设计一个动物乐园程序&#xff0c;展示不同类型动物的行为特点&#xff0c;要求使用多态特性实现。 1. 基础类设计&#xff08;已给出部分代码&#xff09; // 基类&#xff1a;动物 abstract…...

SAP系统中的借货

问题&#xff1a;什么是借贷&#xff1f; 解答&#xff1a;记账符号反映的是各种经济业务数量的增加和减少。 二&#xff1a;怎么区分借贷增减&#xff1f; 解答&#xff1a;“借”和“贷”何时为增加、何时为减少&#xff0c;必须结合账户的具体性质才能准确说明…...