三问了解哈希表和哈希冲突
什么是哈希表?
哈希表也叫散列表,它是基于数组的。这间接带来了一个优点:查找的时间复杂度为 O(1)
、当然,它的插入时间复杂度也是 O(1)
。还有一个缺点:数组创建后扩容成本较高。
哈希表中有一个“主流”思想:转换。一个重要的概念是将「键」或「关键字」转换成数组下标。这由“哈希函数”完成。
什么是哈希函数?
由上,其作用就是将非 int 的键/关键字转化为 int 的值,使可以用来做数组下标。
比如,HashMap 中就这样实现了哈希函数:
static final int hash(Object key){int h;return (key==null)?0:(h=key.hashCode())^(h>>>16); // 通过异或提高hash的“散列度”,降低冲突
}
其中利用了 hashCode 完成转换。虽然哈希函数有很多种实现,但都应当满足这三点:
- 计算得到的是非负整数;
- 如果
key1==key2
,则hash(key1)==hash(key2)
; - 如果
key1!=key2
,则hash(key1)!=hash(key2)
;
- 并不是所有的键/关键字都需要被转换才能做下标(索引)
- 就像 JS 中也有类似的、但仅用于检测键是否能用来做数组下标的方法:JavaScript数组索引检测中的数据类型问题
什么是哈希冲突?
上面提到了 hashMap —— 一个java中提供的数据集。我们先来了解下:首先,hashMap 本质上是一个容器,它为了达到快速索引的目的,使用了数组结构“快速定位”的特性。
hashMap 中为了更快找到插入的值,建立了插入值和数组下标的关系:pos(下标)=key(值)%size(数组大小)
。
比如:数组长度为10
- 插入100,有100%10=0;
- 插入201,有201%10=1;
- 插入403,有403%10=3;
但是如果这样设计的话,我现在再插入200,会怎么样?
这就是数组的一个缺点:插入特殊值比较“费劲”。不如我们干脆将数组涉及成这样:
引入链表特性,一个节点就包括一个值和一个next指针。
现在再插入上面那些值,就变成了这样:
这时候如果再插入值300,怎么做?
类似这样(当两个或以上的key的pos相同,且key不同)其实就是我们提到的“hash冲突”,而 hashMap 中解决hash冲突的方法就是上面说的“单链表”!
但是这又有一个问题:虽然用有序链表的方式可以减少不成功的查找时间(因为只要有一项比查找值大,就说明没有我们需要查找的值),但是不能加快成功的查找。如果冲突的链表太长,则链表查找时需要从“头”遍历的劣势就暴露出来了 —— 针对这个问题,JDK1.8后用 红黑树 做了优化!
但是我们先撇开红黑树,用单链表的形式说明一下哈希表的操作:
/*** 链表基类:链表法解决哈希冲突用的是有序链表!
*/
public class SortedLinkList {private Link first;public SortedLinkList(){first = null;}/*** 链表插入* @param link*/public void insert(Link link){int key = link.getKey();Link previous = null;Link current = first;while (current!=null && key >current.getKey()){previous = current;current = current.next;}if (previous == null)first = link;elseprevious.next = link;link.next = current;}/*** 链表删除* @param key*/public void delete(int key){Link previous = null;Link current = first;while (current !=null && key !=current.getKey()){previous = current;current = current.next;}if (previous == null)first = first.next;elseprevious.next = current.next;}/*** 链表查找* @param key* @return*/public Link find(int key){Link current = first;while (current !=null && current.getKey() <=key){if (current.getKey() == key){return current;}current = current.next;}return null;}
}
链表法哈希表插入:
public void insert(int data) {Link link = new Link(data);int key = link.getKey();int hashVal = hash(key);array[hashVal].insert(link);
}
链表法哈希表查找:
public Link find(int key) {int hashVal = hash(key);return array[hashVal].find(key);
}
链表法哈希表删除:
public void delete(int key) {int hashVal = hash(key);array[hashVal].delete(key);
}
除了链表法,解决哈希冲突还有一个方法:开放寻址法。
在开放地址法中,若数据不能直接存放在哈希函数计算出来的数组下标时,就需要寻找其他位置来存放。在开放地址法中有三种方式来寻找其他的位置,分别是
- 线性探测
- 二次探测
- 再哈希法
三问了解哈希表和哈希冲突相关推荐
- python 哈希表_哈希表哪家强?编程语言找你来帮忙!
点击关注上方"五分钟学算法", 设为"置顶或星标",第一时间送达干货. 转自编程技术宇宙 哈希表华山论剑 比特宇宙编程语言联合委员会准备举办一次大会,主题为哈希 ...
- 哈希表及哈希冲突解决办法
哈希表及哈希冲突解决办法 目录 什么是哈希表? 哈希表的数据结构 哈希冲突 哈希冲突解决办法 1. 什么是哈希表? 哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直 ...
- 除留余数法构造哈希表_哈希表算法原理
基本概念 哈希表(Hash Table)是一种根据关键字直接访问内存存储位置的数据结构.通过哈希表,数据元素的存放位置和数据元素的关键字之间建立起某种对应关系,建立这种对应关系的函数称为哈希函数. 哈 ...
- ds哈希查找—二次探测再散列_大白话之哈希表和哈希算法
哈希表概念 哈希表(散列表),是基于关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数(哈希函数 ...
- 大白话之哈希表和哈希算法
哈希表概念 哈希表(散列表),是基于关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数(哈希函数 ...
- 哈希表构造与处理冲突方法
我们知道:哈希表是一个固定大小的数组,数组的每个元素是一个链表(单向或双向)的头指针.如果Key一样,则在一起,如果Key不一样,则不在一起.哈希表的查询是飞快的.因为它不需要从头搜索,它利用Key的 ...
- LeetCode哈希表(哈希集合,哈希映射)
文章目录 哈希表 1.原理 2.复杂度分析 题目&推荐列表 哈希集合的应用 0.常用解题模板 1.lc217 存在重复元素 2.lc136 只出现一次的数字 3.快乐数 哈希映射的应用 0.常 ...
- 哈希表(哈希函数和处理哈希冲突)_20230528
哈希表(哈希函数和处理哈希冲突) 前言 关于哈希表的主题的小记原计划5月23日完成,由于本人新冠阳性,身体发烧乏力,周末感觉身体状况稍加恢复,赶紧打开电脑把本文完成,特别秉承"写是为了更好地 ...
- [算法入门笔记] 9. 哈希表与哈希函数
文章目录 1. 哈希表与哈希函数的实现 2. 设计RandomPool结构 3. bitmap 3.1 概述 3.2 常用操作 3.2.1 存储数据 3.2.2 添加操作 3.2.3 删除操作 3.2 ...
最新文章
- Linux文件系统:概览(思维导图)
- asp.net获取网站路径
- oracle rowid mysql_相当于Oracle的RowID在MySQL中
- Web Dynpro Controller
- 判断是否在数组中,若在输入其下标,否则输入-1
- MySQL笔记-事务理论及并发存在的三个问题(脏读、不可重复读、幻读)演示
- java中random方法取值范围_Java中的Random()函数
- 在Linux上安装JDK9
- iptables: Resource temporarily unavailable.问题
- asp木马伪装成图片或其它,上传漏洞终极解决方法
- PHP跨域获取session
- 深度学习花书+机器学习西瓜书电子版我找到了
- 构建系统发育树~序列对比 MEGA、MAFFT(图文教程)
- 『天涯杂谈』十大古今名人语录经典(2007版)
- Redis trouble21 -- aof持久化导致redis命令阻塞
- html动态背景分享,酷炫一款动态背景(HTML +js canvas)
- 七夕超多表情包入侵 - 100%提升博客美感(六千粉丝福利)!
- Hive权限管理,增加用户,授权
- 怎么在Ubuntu手机上发送短信及拨打电话
- 通达信 服务器 修改,通达信验证服务器数据库修改
热门文章
- 别让企业发展成为悲剧
- MPAndroidChart—— pieChart 属性详解
- verilog牛客网刷题代码汇总
- QT 调用vs写的dll 使用OutputDebugString输出调试信息
- Silver Cow Party (最短路)
- web-前端设计之鼠标悬停样式
- arcgis python二次开发_arcgis二次开发python_arcgis二次开发是什么_arcgis二次开发
- 不服不行!终于有人把AMS和WMS讲明白了!
- 命令提示符(cmd)中的tracert命令详解
- JAVA小程序简单学籍系统参考代码,登陆小程序,Jtree //Jtree,JDBC,Jframe