哈希表的原理

哈希概念

线性表、树结构的查找方式都是以关键字的比较为基础,查找效率比较低,顺序表的时间复杂度是O(n),平衡树中为树的高度,即O(logn),搜素的效率取决于搜索过程的元素比较次数。

理想的搜素方法:可以用不经过比较,一次直接从表中得到要搜素的元素。如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与他的关键字之间能够建立一一映射的关系,那么在查找元素的时候,就可以很快寻找到该元素,这就是哈希的思想.

哈希函数

插入元素

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

搜素元素

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

此方法即为哈希(散列)方法,哈希(散列)方法中使用的转换函数称之为哈希(散列)函数,构造出来的结构就是哈希表(hashTable)(或者散列表)。

例如:数据集合{1,7,6,4,5,9};

哈希函数设置为:hash(key)= key%capacity;(capacity代表的是底层空间总大小可以理解成元素个数)

 用该方法进行搜素的时候不必多次进行比较可以直接找到想找的关键字,但是我们就会出现一个问题:如果再次插入一个44怎么办呢?这就会引出下面的部分,哈希冲突。

哈希冲突:

概念:

对于两个关键字ki,kj(i != j)有ki != kj,但是有:Hash(ki)== Hash(kj)即:不同的关键字通过哈希函数计算出相同的哈希地址,这种现象称之为哈希冲突。

冲突的避免

首先我们要明确疑点,由于我们哈希表底层数组容量往往小于实际要存储的数量,这就导致了一个问题,冲突是必然的,但是我们可以降低冲突率。

哈希函数的设计

1、直接定制法

取关键字的某个线性函数为散列地址:Hash(key)=A*key+B (即是一个y=ax+b的函数,如计数排序数字91存储在(91-90)的下标上)优点:简单、均匀 缺点需要事先知道关键字的分布情况 使用场景:适合查找比较小且连续的情况。

2、除留余数法

这个就是我们上面所介绍的方法,标准的官方说法是设散列表中允许的地址数为m(如果10个数据m的范围就是0-9),取一个不大于m的数,但是最接近或者等于m的质数p作为除数,按照哈希函数Hash(key)= key%p(p<=m),将关键字码转换为哈希地址。

还有很多的方法,但是使用的很少,所以这里不过多介绍。

负载因子调节

散列表的载荷因子定义为:\alpha=填入表格的元素/散列表的长度

在java系统库中限制载荷因子为0.75如果大于这个数字就需要,降低载荷因子。

哈希冲突的解决

哈希冲突的常见的两种解决方案就是:闭散列和开散列。

闭散列:也叫开放定址法,当哈希表没有被填满,说明哈希表还有空位置,那么可以把key存放到冲突位置的下一个空位置去。那么如何寻找下一个空位置呢?

1、线性探测

比如上面的场景,现在需要插入元素44,先通过哈希函数计算哈希地址,下标是4,所以理论上应该插入到4的位置,但是该位置已经存放了元素4,即发生了哈希冲突。

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

 采用闭散列处理哈希冲突的时候,不能随便物理删除哈希表已经有的元素,若直接删除元素会影响其他元素的搜索。比如删除4,如果直接删除4,那么在查找44的时候就会受到影响。因此线性探测采用标记的伪元素来删除一个元素。

2、二次探测

线性探测的缺陷是产生冲突的元素堆积到一块,这与其找下一个元素位置有关系,因为找空位置的方式就是挨着往后逐个去找,因此二次探测为了避免这样的问题,找下一个空位置的方法为:Hi=(H0+i²)%m或者Hi=(H0-i²)%m其中:i=1,2,3....H0是通过哈希函数计算出元素所在位置,m是表的大小。

因此:闭散列表的最大缺陷就是空间利用率低,这也是哈希的缺陷。

开散列/哈希桶(重点)

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

 

开散列,可以认为把一个大集合中的搜素问题转化到小集合中进行。

代码实现:

public class Hashbucket {static class Node{private int key;private int value;private Node next;public Node(int key, int value) {this.key = key;this.value = value;}}public Node[] array;public int useSize;private static final float DEFAULT_LOAD_FACTOR = 0.75f;public Hashbucket() {array=new Node[10];}public void put(int key,int value){Node node=new Node(key,value);int index= node.key%array.length;Node cur=array[index];//java1.8之后采用的是尾插法 这里采用头插法while(cur!=null){if(cur.key==key){cur.value=value;return;}cur=cur.next;}node.next=array[index];array[index]=node;useSize++;if(loadFactor()>DEFAULT_LOAD_FACTOR){resize();}}public void resize(){//二倍扩容Node[] tmpArray=new Node[array.length*2];for (Node node : array) {Node cur = node;while (cur != null) {Node curNext = cur.next;int index = cur.key % tmpArray.length;//头插法cur.next = tmpArray[index];tmpArray[index] = cur;cur = curNext;}}array=tmpArray;}public float loadFactor(){return array.length*1.0f/useSize;}public int get(int key){int index=key%array.length;Node cur=array[index];while(cur!=null){if(cur.key==key){return cur.value;}cur=cur.next;}return -1;}
}

这个代码中这个扩容部分我们要仔细的说一说,但负载因子大于0.75的时候,我们需要降低哈希冲突,因为我们的元素个数是一定的,所以我们就需要增大散列表的大小,但是当我们扩容的时候,我们会打乱原来的散列表,比如原来4和14都是在节点4的位置,当我们二倍扩容的时候我们就需要将14放到节点14的位置。

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

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

相关文章

Spring-Interceptor拦截器

使用步骤 申明拦截器bean&#xff0c;并实现HandlerInterceptor接口 true为放行&#xff0c;false为拦截 2.定义配置类&#xff0c;继承WebMvcConfigurationSupport&#xff0c;实现addInterceptors方法&#xff0c;该方法调用具体的拦截器进行拦截 也可以在配子类通过实现W…

【Elasticsearch】DSL查询文档

目录 1.DSL查询文档 1.1.DSL查询分类 1.2.全文检索查询 1.2.1.使用场景 1.2.2.基本语法 1.2.3.示例 1.2.4.总结 1.3.精准查询 1.3.1.term查询 1.3.2.range查询 1.3.3.总结 1.4.地理坐标查询 1.4.1.矩形范围查询 1.4.2.附近查询 1.5.复合查询 1.5.1.相关性算分 …

Set与Map的使用 + 二叉搜索树与哈希桶的大白话讲解和图解+完整代码实现(详细注释)

文章目录 前言一、Set与Map概念及场景模型纯Key模型Key-Value模型 Map 的使用Set 的使用 二、二叉搜索树什么是二叉搜索树代码实现二叉搜索树查找操作插入操作删除操作(难点)cur这个节点没有左子树(cur.left null)cur这个节点没有右子树(cur.right null)cur这个节点没有左右子…

PyTorch深度学习实战(5)——计算机视觉

PyTorch深度学习实战&#xff08;5&#xff09;——计算机视觉 0. 前言1. 图像表示2. 将图像转换为结构化数组2.1 灰度图像表示2.2 彩色图像表示 3 利用神经网络进行图像分析的优势小结系列链接 0. 前言 计算机视觉是指通过计算机系统对图像和视频进行处理和分析&#xff0c;利…

【Python】正则表达式语法入门

目录 正则表达式 1、点&#xff1a;匹配所有字符 2、星号&#xff1a;重复匹配任意次 3、加号&#xff1a;重复匹配多次 4、花括号&#xff1a;匹配指定次数 5、贪婪模式和非贪婪模式 6、反斜杠&#xff1a;对元字符的转义 7、方括号&#xff1a;匹配几个字符之一 8、…

异地使用PLSQL远程连接访问Oracle数据库【内网穿透】

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 转载自cpolar极点云文章&#xff1a;公网远程连接…

cjson的内存泄漏案例

1、当我们使用下面这些创建json对象时&#xff0c;需要用cJSON_Delete();释放&#xff0c;&#xff08;当然&#xff0c;释放父JSON对象后&#xff0c;子JSON对象也会被释放&#xff09; 2、多次释放同一内存空间 在recv_write_property函数中的data&#xff0c;在Equipment_re…

Html基础知识学习——兼容问题与解决方法(十六)

文章目录 1.计算一定要精确&#xff0c;不要让内容的宽高超出我们设置的宽高&#xff0c;在IE6下内容会撑开设置好的宽高2.元素浮动&#xff0c;宽度需要内容撑开&#xff0c;就给里面的块元素都加浮动3.在ie6.ie7下元素要浮动并在同一行 就给这些元素都加浮动4.注意标签嵌套规…

【玩转Linux操作】Linux进程(进程基本介绍,父子进程,终止进程,进程树)

&#x1f38a;专栏【玩转Linux操作】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;进程的基本介绍&#x1f354;显示系统执行的进程⭐…

微服务 云原生:K8S 核心组件

参考 Kubernetes 官方文档&#xff0c;简要概述 Kubernetes 中的核心组件用途及部分原理。 一个 K8S 集群&#xff0c;可以分为两个部分&#xff1a; 控制平面(Control Plane)。它是一套管理系统&#xff0c;专门来管理集群节点和服务&#xff0c;为集群做出全局决策&#xff…

使用 @Autowired 为什么会被 IDEA 警告,应该怎么修改最佳?

# 问题原因 关于这个问题&#xff0c;其实答案相对统一&#xff0c;实际上用大白话说起来也容易理解。 1.初始化问题 先看一下Java初始化类的顺序&#xff1a;父类的静态字段 > 父类静态代码块 > 子类静态字段 > 子类静态代码块 > 父类成员变量 > 父类构造代码块…

Linux系统使用(超详细)

目录 Linux操作系统简介 Linux和windows区别 Linux常见命令 Linux目录结构 Linux命令提示符 常用命令 ls cd pwd touch cat echo mkdir rm cp mv vim vim的基本使用 grep netstat Linux面试题 Linux操作系统简介 Linux操作系统是和windows操作系统是并列…

数组与指针

博客内容&#xff1a;数组与指针 文章目录 一、 数组&#xff1f;指针&#xff1f;1.区别与联系大小赋值存储位置 二、指针数组、数组指针&#xff1f;二维数组和二级指针&数组名与数组的区别总结 一、 数组&#xff1f;指针&#xff1f; 数组 相同类型数据的集合 指针 指…

使用SpringBoot+React搭建一个Excel报表平台

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 Excel报表平台是一款功能强大、操作简单的系统平台&#xff0c;可以帮助用户上传…

【C++/嵌入式笔试面试八股】二、24.TCP三次握手四次挥手 | TCP可靠性

TCP三次握手四次挥手 64.TCP头部中有哪些信息?❤️ TCP数据报格式(左图) UDP数据报格式也放这(右图),不具体解释了。 结合三次握手四次挥手来看 端口: 区分应用层的不同应用进程 扩展:应用程序的端口号和应用程序所在主机的 IP 地址统称为 socket(套接字),IP:端口…

如何在 Windows 中免费合并 PDF 文件 [在线和离线]

PDF是一种广泛使用的文件格式&#xff0c;具有兼容性好、安全性高、易于打印、方便浏览等众多优点。在工作和学习过程中&#xff0c;经常需要将同一类型的PDF文件合并起来&#xff0c;以方便传输和查看&#xff0c;使得合并PDF文件成为一种重要的数据整合方法。 如果您想知道如…

1、Kubernetes 概述和架构

目录 一、基本介绍 二、kubernetes功能和架构 2.1、 概述 2.2 、功能 &#xff08;1&#xff09;自动装箱 &#xff08;2&#xff09;自我修复(自愈能力) &#xff08;3&#xff09;水平扩展 &#xff08;4&#xff09;服务发现 &#xff08;5&#xff09;滚动更新 &a…

Linux进程理解【环境变量】

Linux进程理解【环境变量】 提到环境变量&#xff0c;大家可能有些陌生&#xff0c;如果编写过Java就知道&#xff0c;编写Java需要提前安装JDK&#xff0c;这个操作就是配置Java的编码环境&#xff0c;在Linux中当然也少不了环境变量&#xff0c;下面我们就一起来看看 文章目…

Node.js 版本管理工具 n 使用指南

Node.js 版本更新很快&#xff0c;目前 node v20.x 已经发布&#xff0c;我们在使用时避免不了会需要切换不同的 Node.js 的版本来使用不同版本的特性。 所以就出现了像 windows 上的 nvm&#xff0c;MacOS 上的 n 工具&#xff0c;本文就介绍一下如何使用 n 管理 Node.js 的版…

Django_haystack全文搜索

haystack是全文搜索的框架&#xff0c;支持whoosh、solr、Xapian、Elasticsearc四种全文检索引擎&#xff0c;点击查看官方网站。 whoosh是用纯Python编写的全文搜索引擎&#xff0c;虽然性能比不上sphinx、xapian、Elasticsearc等&#xff0c;但是无二进制包&#xff0c;程序…