java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
版权声明:觉得此文有用的,不嫌麻烦的,就留个言呐,或者点个赞呐(额,就是文章底部的“顶”啦),要是嫌弃麻烦呢,也麻烦点个赞嘛,要是实在不想点赞呢,也不是不可以。 但是,你要是想踩一脚呢,那还是赶紧,马上,快快的闪人。 小心我手里三十米长的大刀。 哼哼。想想都怕 !!!
一)哈希表简介
非哈希表的特点:关键字在表中的位置和它之间不存在一个确定的关系,查找的过程为给定值一次和各个关键字进行比较,查找的效率取决于和给定值进行比较的次数。
哈希表的特点:关键字在表中位置和它之间存在一种确定的关系。
哈希函数:一般情况下,需要在关键字与它在表中的存储位置之间建立一个函数关系,以f(key)作为关键字为key的记录在表中的位置,通常称这个函数f(key)为哈希函数。
hash : 翻译为“散列”,就是把任意长度的输入,通过散列算法,变成固定长度的输出,该输出就是散列值。
这种转换是一种压缩映射,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。
简单的说就是一种将任意长度的消息压缩到莫伊固定长度的消息摘要的函数。
hash冲突:(大师兄自己写的哦)就是根据key即经过一个函数f(key)得到的结果的作为地址去存放当前的key value键值对(这个是hashmap的存值方式),但是却发现算出来的地址上已经有人先来了。就是说这个地方要挤一挤啦。这就是所谓的hash冲突啦
二)哈希函数处理冲突的方法
1)开放定址法:
其中 m 为表的长度
对增量di有三种取法:
线性探测再散列 di = 1 , 2 , 3 , ... , m-1
平方探测再散列 di = 1 2 , -12 , 22 , -22 , 32 , -32 , ... , k2 , -k2
(大师兄备注:吗单,上面的平方探测再散列是加1的平方;减1的平方,加2的平方,减2的平方,加3的平方,减3的平方。。。加k的平方,减k的平方。卧擦,老师你能再坑点么?法科。要是你直接看这个平方探测再散列的di是怎么来的,不一定能看懂老师ppt的这个写法,是平方的意思。上面的红色字呢,相当于是老师的ppt,是对应上面的图片一起看的。)
随机探测再散列 di 是一组伪随机数列
例子:
我在上面的这个配图底部写的那个红色的12,我当时测试的时候,不知道这个12,也就是上面增量 di 的由来。不知道,限制知道了,那是1的2次方。。。。老师懒得或者说不会给数字打角标。
2)链地址法
上面这个只是老师的ppt,下面放上自己亲自整的测试。
先按照ppt上的hash算法:h(key) = key % 7,算出来对应的hash值,这个hash值暂时就决定,当前的这个值,存放在数组的位置。
都算完之后,就可以,按照这个hash值,依次的,把这些数,都放在下面的数组上。然后就有我自己的这个截图。
和上面的ppt推算的是一致的。
这个做法就是Java的HashMap就是这么实现的,简单的解释下,这个HashMap源码的这个链表产生机制。
在put()方法里面,最后部分有个如下的调用。
addEntry(hash, key, value, i);
解释下几个参数的意思:
1,hash:就是根据key算出来的一个值,源码是这么滴--int hash = hash(key);,
这个算出来的这个就相当于是身份证号码,可以唯一确定一个人一样,唯一确定这个map
2,key:key就是我们在往hashmap里面put键值对的时候的key,使用map的时候,不是可以根据key拿到value吗。
3,value:这个同上啦,就是存的键值对的值。
4,i:源码里面是这么滴--int i = indexFor(hash, table.length);实际意思就是这个键值对存放在底层数组的索引下标。
然后这个i,可以对应到ppt上的那个取模之后的值,也就是确定在数组上的下标。
虽然在put的时候,可能会出现扩容的问题,但是在这咱就不考虑这个,只考虑如何生成链表,以及链表上的键值对的顺序。
createEntry(hash, key, value, bucketIndex);
这个方法就是真正的在创建一个节点到数组上。
这几个参数是一样的,和上面解释的一样的意思。
- //先从数组上取下原来的值,给塞到新的节点去,然后把新的节点再放到数组上。
- //也就是后来居上的道理。ppt上画的也就有点毛病了。
- //老师们嘛,就是 混口饭吃,一般都不斤斤计较这东西的。
- void createEntry(int hash, K key, V value, int bucketIndex) {
- Entry<K,V> e = table[bucketIndex];
- table[bucketIndex] = new Entry<>(hash, key, value, e);
- size++;
- }
- static class Entry<K,V> implements Map.Entry<K,V> {
- final K key;
- V value;
- Entry<K,V> next;
- int hash;
- /**
- * Creates new entry.
- */
- Entry(int h, K k, V v, Entry<K,V> n) {
- value = v;
- next = n;
- key = k;
- hash = h;
- }
- //******
上面就是hashmap底层数组上存的元素的model。也是能形成链表的关键,有兴趣的可以看看1.7的hashmap的源码。
3、4)再哈希、建立公共溢出区
3.再hash法,就是算hashcode的方法不止一个,一个要是算出来重复啦,再用另一个算法去算。反正很多,直到不重复为止咯。大师兄猜的
4.建立一个公共溢出区域,就是把冲突的都放在另一个地方,不在表里面。具体实现就 不知道啦,也是大师兄猜的。
2.再哈希法
3.链地址法(Java hashmap就是这么做的)
4.建立一个公共溢出区
看到这个,自个儿还是得静下心来看看hashmap的源码,1.7的简单易懂,我还做了注解,可以看看,链接如下
Java 1.7 的hashmap 的理解,多了红黑树什么的。
转自:http://blog.csdn.net/qq_27093465/article/details/52269862
java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区的更多相关文章
- Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
最近时间有点紧,暂时先放参考链接了,待有时间在总结一下: 查了好多,这几篇博客写的真心好,互有优缺点,大家一个一个看就会明白了: 参考 1. 先看这个明白拉链法(链地址法),这个带源码,很好看懂,只不 ...
- Hash(散列函数)简单应用引出解决散列冲突的四种方法
商店允许顾客通过电话订购商品,并在几天后上门自取.商店的数据库使用客户的电话号码作为其检索的关键字(客户知道自己的电话号码,而且这些电话关键字几乎是唯一的).如何组织商店的数据库,以允许更加高效的进行 ...
- Java中取小数点后两位(四种方法)
摘自http://irobot.iteye.com/blog/285537 Java中取小数点后两位(四种方法) 一 Long是长整型,怎么有小数,是double吧 java.text.D ...
- JAVA中获取文件MD5值的四种方法
JAVA中获取文件MD5值的四种方法其实都很类似,因为核心都是通过JAVA自带的MessageDigest类来实现.获取文件MD5值主要分为三个步骤,第一步获取文件的byte信息,第二步通过Messa ...
- Java 判断字符串是否为空的四种方法、优缺点与注意事项
以下是Java 判断字符串是否为空的四种方法: 方法一: 最多人使用的一个方法, 直观, 方便, 但效率很低: if(s == null ||"".equals(s));方法二: ...
- Hash算法解决冲突的四种方法
Hash算法解决冲突的方法一般有以下几种常用的解决方法 1, 开放定址法: 所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入 公式为 ...
- 【数值分析】误差的分析与减少及Matlab解线性方程的四种方法
1.误差的来源 模型误差:数学模型与实际问题之间的误差 观测误差:测量数据与实际数据的误差 方法误差:数学模型的精确解与数值方法得到的数值解之间的误差:例如 舍入误差:对数据进行四舍五入后产生的误差 ...
- 【Java集合学习】HashMap源码之“拉链法”散列冲突的解决
1.HashMap的概念 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射. HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io ...
- Python:说说字典和散列表,散列冲突的解决原理
散列表 Python 用散列表来实现 dict.散列表其实是一个稀疏数组(总是有空白元素的数组称为稀疏数组).在一般书中,散列表里的单元通常叫做表元(bucket).在 dict 的散列表当中,每个键 ...
随机推荐
- 类型:Oracle;问题:oracle 时间加减;结果:ORACLE 日期加减操作
ORACLE 日期加减操作 无论是DATE还是timestamp都可以进行加减操作. 可以对当前日期加年.月.日.时.分.秒,操作不同的时间类型,有三种方法: 1 使用内置函数numtodsinter ...
- 异常 android.content.res.Resources$NotFoundException: String resource ID #0x61
09-09 16:08:41.554: E/Weaver(13140):09-09 16:08:41.554: E/Weaver(13140): android.content.res.Resourc ...
- ARQ
自动重传请求(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层和传输层的错误纠正协议之一.它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输.如果 ...
- .Net时间运算 - DateTime类,TimeSpan类
DateTime类是.Net中用于处理时间类型数据的. 一.字段 MaxValue 表示 DateTime 的最大可能值.此字段为只读. MinValue 表示 DateTime 的最小可能值 ...
- Oracle pl/sql 基础入门语法
PL/SQL是一种块结构的语言,这意味着PL/SQL程序被划分和编写代码的逻辑块.每块由三个子部分组成:1 声明 此部分开头使用关键字DECLARE.它是一个可选的部分,并限定在该程序中使用的 ...
- Arduino Uno 在win7 64位下的驱动问题
1.解压[mdmcpq.inf_amd64_neutral_fbc4a14a6a13d0c8.rar],将[mdmcpq.inf_amd64_neutral_fbc4a14a6a13d0c8]文件夹复 ...
- [poj3159]Candies(差分约束+链式前向星dijkstra模板)
题意:n个人,m个信息,每行的信息是3个数字,A,B,C,表示B比A多出来的糖果不超过C个,问你,n号人最多比1号人多几个糖果 解题关键:差分约束系统转化为最短路,B-A>=C,建有向边即可,与 ...
- [poj2318]TOYS(直线与点的位置关系)
解题关键:计算几何入门题,通过叉积判断. 两个向量的关系: P*Q>0,Q在P的逆时针方向: P*Q<0,Q在P的顺时针方向: P*Q==0,Q与P共线. 实际就是用右手定则判断的. #i ...
- Node 中的 stream (流)
流的概念 流(stream)在 Node.js 中是处理流数据的抽象接口(abstract interface). stream 模块提供了基础的 API .使用这些 API 可以很容易地来构建实现流 ...
- 一个ButtonDemo序(遇到的问题,以及在大牛的帮助下,如何解决的。)
问题1: public ButtonDemo(){ //ImageIcon leftButtonIcon=new ImageIcon("images/a.png"); ImageI ...