目录

1哈希表的概念:

1.1哈希表的插入图示:

1.2哈希表的查询图示:

2.哈希冲突

2.1哈希冲突的概念:

2.2避免冲突

2.2.1哈希函数设计

2.2.2负载因子的调节

3.解决冲突

3.1闭散列:

3.2开散列/(哈希桶)

4.哈希表的实现


1哈希表的概念:

1.1哈希表的插入图示:

1.2哈希表的查询图示:

上图解释了如何以哈希的方式存储数据了;那么数据该如何读取呢?请看下图!

2.哈希冲突

2.1哈希冲突的概念:

对于 两个数据元素 的关键字 K1 和 K2(互不相等),但有:哈希函数:Hash(k1) == Hash(K2) ,即:不同的关键字通过相同的哈希函数计算出了相同的哈希地址,这种现象成为哈希冲突或 哈希碰撞。把具有不同关键码,但却具有相同的哈希地址的数据元素称为 “同义词”。

2.2避免冲突

哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这也就导致了一个问题,那就是冲突是必然会发生;虽然冲突是必然发生的;但是我们能做到的是尽量降低冲突的概率.

如何有效避免哈希冲突呢?从以下两个方面入手:哈希函数的设计,负载因子的调节!

2.2.1哈希函数设计

哈希函数设计不合理是引起哈希冲突的一个重要原因;那么常见的哈希函数主要是以下两种!

1. 直接定制法:

取关键字的某个线性函数为散列地址:HashKey= A*Key + B 优点:简单、均匀 缺点:需要事先知道关 键字的分布情况 使用场景:适合查找比较小且连续的情况

2. 除留余数法:

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

2.2.2负载因子的调节

负载因子的定义: a = 填入表中的元素个数 / 哈希表的长度

通俗的理解就是:当哈希表长度一定时;随着插入表中元素的增加;负载因子(a)就会增大;而负载因子越大,冲突产生的概率就越大;所以我们可以通过降低负载因子来降低冲突率.

负载因子与冲突率的关系如下:

 那么怎么调节负载因子呢?

由定义公式可知:a = 填入表中的元素个数 / 哈希表的长度;

我们可以通过增大分母来使负载因子a降低;也就是将哈希表的长度增长,通俗的讲:将数组扩容;

3.解决冲突

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

3.1闭散列:

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以
把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢
有两种方式:线性探测 和 二次探测
1.线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。(通俗的理解就是:该位置发生冲突之后,直接在该位置后找下一个空位插入即可)

虽然是线性探测解决了寻找空位的问题,但是又引来了另一个问题:那就是会使产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就是挨 着往后逐个去找,因此二次探测为了避免该问题.

2.二次探测:找下一个空位置的方法为:H(i) = (H0 + i^2 ) % m, 或者:H(i)= (H0 - i^2) % m。其中:i = 1,2,3…, 是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小。(通俗的理解就是:虽然也是找空位插入,但是在找空位的时候,跟上一个找的位置隔的更远了,也就使的冲突的数据分的更加开了)

闭散列的缺陷:
闭散列虽然在一定程度上解决了哈希冲突;但是他存在着缺陷:例如不能随意物理删除元素;采用闭散
列处理哈希冲突时,不能随意物理删除哈希表中的已有元素,若直接删除元素会影响到其他元素的寻
找,这就导致了没有用的数据仍然存,使得空间利用率比较低!
那怎么办呢?就由开散列来解决!

3.2开散列/(哈希桶)

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关
键码归于同一子 集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各
链表的头结点存储在哈希表中.
文字比较抽象,直接上图:
开散列,可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了!

4.哈希表的实现

public class HashBucket {static class Node {public int key;public int val;public Node next;public Node(int key, int val) {this.key = key;this.val = val;this.next = null;}}private Node[] array;public int usedsize;public HashBucket() {this.array = new Node[10];this.usedsize = 0;}public void put(int key, int val) {//1.确定下标==哈希函数int index = key % this.array.length;//2.遍历这个下标的链表Node cur = array[index];//头插法while (cur != null) {//如果key已经存在 更新valif (cur.key == key) {cur.val = val;return;}cur = cur.next;}//3.cur == null 当前数组下标下的链表 没有key 则将其以头插法进行插入Node node = new Node(key, val);node.next = array[index];array[index] = node;this.usedsize++;//4.判断是否需要扩容if (loadFactor() >= 0.75) {//扩容resize();}}public double loadFactor() {return this.usedsize * 1.0 / this.array.length;}public void resize() {//自己创建新的数组 该数组是原本数组长度的两倍Node[] newArray = new Node[2 * this.array.length];//需要把原本数组里所存储的数据全部重新进行哈希 因为数组的长度变了 哈希函数里的数值就变了 所以需要重新哈希//遍历原本的哈希桶//最外层循环 控制数组的下标for (int i = 0; i < array.length; i++) {Node cur = array[i];Node curNext = null;while (cur != null) {//记录cur.nextcurNext = cur.next;//重新确立新的下标 然后进行头插法int index = cur.key % newArray.length;cur.next = newArray[index];newArray[index] = cur;cur = curNext;}}this.array = newArray;}public int get(int key) {//以什么样的方式存储的 就以什么样的方式取出int index = key % this.array.length;Node cur = array[index];while (cur != null) {if (cur.key == key) {return cur.val;}cur = cur.next;}return -1;}
}

开局一张图帮你充分理解哈希表(散列表)相关推荐

  1. 7个GIF动图帮你瞬间理解三角函数

    7个GIF动图帮你瞬间理解三角函数 蝌蚪五线谱 百家号04-2120:53 图片来源:IMGUR 三角函数是数学中研究三角形的一个分支,专门阐述三角形的角度和对应边的关系. 有趣的是,定义边角关系的三 ...

  2. 【JavaScript】JavaScript模拟实现面向对象一张图帮助你深刻理解原型链和原型对象

    文章目录 一.JavaScript模拟面向对象 1.函数是类 2.函数中各种变量的声明 3.关于函数内的this 小结:JavaScript中函数是什么? 4.练习:面向对象思想编写Complex类 ...

  3. 一张图帮你看懂 iPhone 6 Plus 的屏幕分辨率

    一张图帮你看懂 iPhone 6 Plus 的屏幕分辨率 几天前发布的 iPhone 6 Plus 官方标称屏幕是 1920 x 1080 的,但是在 Xcode 中我们发现模拟器的屏幕其实是看似奇怪 ...

  4. 几张图帮你捋清“中国金融机构体系”

    原文链接:几张图帮你捋清"中国金融机构体系" - 走看看 (zoukankan.com) 几张图帮你捋清楚,中国金融机构的关系- 金融业务有哪些? 金融业务有:银行业.证券业.保险 ...

  5. 几张图帮你理解 docker 基本原理及快速入门

    http://hainiubl.com/topics/13 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目.它基于 Goog ...

  6. 一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 前言 有时候我们需要在应用启动时执行一些代码片段,这些片 ...

  7. 三次简化一张图:一招理解LSTM/GRU门控机制

    机器之心专栏 作者:张皓 RNN 在处理时序数据时十分成功.但是,对 RNN 及其变种 LSTM 和 GRU 结构的理解仍然是一个困难的任务.本文介绍一种理解 LSTM 和 GRU 的简单通用的方法. ...

  8. 一张图30分钟带你入门python-大数据时代来了!神级程序员一张图帮你梳理Python脉络,快速入门...

    python语言是我目前为止用的最爽的语言,因为它真的很优美.虽然c,c++,java也非常的强大和伟大,但是每一种语言伟大的背后都是有一定的时代背景. 在PC时代大量的嵌入式的设备,底层的代码,以及 ...

  9. 一张图就让你理解K-Means算法!!

    K-Means是无监督学习中最经典的聚类算法 一.什么是无监督学习?什么是聚类? 无监督学习简单来说就是没有标签变量,即没有y值,仅仅依靠特征变量x进行学习.通常以"是否有标签变量y&quo ...

最新文章

  1. 是时候装逼了,试试 IDEA 解决 Maven 依赖冲突的高能神器!
  2. 话说Ubuntu和FreeBSD将要合成一个新的版本:UbuntuBSD
  3. CTabCtrl - 如何使用TabCtrl控件
  4. 将构件发布到私有的nexus maven 仓库
  5. [wikioi]奇怪的梦境
  6. python识别出蓝色_OpenCVPython——无法检测蓝色对象
  7. Git——创建版本库【git init】
  8. 3.4 神经网络概述、tensorflow2实现——python实战
  9. 《图解HTTP》读书笔记(二:各种协议与HTTP协议之间的关系)
  10. c语言printf * abd bc,C语言练习题_答案版本
  11. mvc:annotation-driven:注解驱动
  12. WordPress付费资源素材下载主题 总裁CeoMax主题
  13. android:ems 属性
  14. 网络神采关键词过滤NET插件
  15. 32位与64位CPU字长
  16. js 监听esc按键
  17. [arch Linux] 使用grub实现Linux和Windows双系统的引导
  18. 计量经济学计算机数据分析,如何用计量经济学作实证分析..doc
  19. WPF 改进 WrapPanel 右侧填充
  20. 汇编语言里 eax, ebx, ecx, edx, esi, edi, ebp, esp这些都是什么意思啊? [

热门文章

  1. 列表xcode项目下所有的lnfo.plist
  2. 苹果cms重复采集重名视频解决方法
  3. 10.24程序员节疑问:沈从文的编程功底应该很厉害吧?
  4. 在线视频地址 ios播放在线视频
  5. 一周热图|王珞丹创立宠物用品品牌;超模何穗亮相雀巢冷萃自由大秀;乐高试点有声与盲文拼搭指南...
  6. matlab绘制分段函数,二维函数
  7. 几个Android云测试
  8. css怎么随着鼠标移动,利用CSS sprites制作随着鼠标移动的动画背景
  9. 电动车锂电池行业前景广阔,啰马锂服帮助企业、门店“降本增效”
  10. 2021年上半年最接地气的Android面经,隔壁都馋哭了