散列

一.什么是散列

散列使用一个散列函数,将一个键映射到一个索引上。
散列非常高效。使用散列将耗费O(1)时间来查找、插入、及删除一个元素。

映射表是一种用散列实现的数据结构,映射表是一种存储条目的容器,每个条目包含两个部分:一个键(key)和一个值(value)。键又称为搜索键用于查找对应的值。
映射表(map)又称为字典(dictionary)、散列表(hash table)或者关联数组(associate array)。

Java合集框架定义了java.util.Map接口,三个具体的的实现为java.util.HashMap、java.util.linkedHashMap以及java.util.TreeMap。java.util.HashMap使用散列实现,java.util.linkedHashMap使用linkedList,java.util.TreeMap使用红黑树。

 

二.散列函数和散列码

1.散列函数
将键映射到散列表的索引上的函数称为散列函数(hash function)。理想的,将每个搜索的键映射到散列表中的不同索引上,这样的函数称为完美散列函数。然而,很难找到一个完美的散列函数,当两个或更多的键映射到一个散列值上的时候,我们称之为产生了一个冲突(collision)。

典型的散列函数首先将搜索键转换成为一个整数值,称之为散列码。然后将散列码压缩为散列表中的索引。

2.equals和hashCode
Java的根类Object具有hashCode方法,返回一个整数的散列码。默认的,该返回值是一个该对象的内存地址。hashCode一般有如下约定:
1)当equals方法被重写时,应该重写hashCode方法,以保证两个相等的对象返回同样的散列码。
2)程序执行中,如果对象的数据没有被修改,则多次调用hashCode将返回同样的整数。
3)两个不相等的对象可能具有同样的散列码,但是应该在实现hashCode方法时避免太多这样的情形出现。

3.基本数据类型的散列码
对于byte、short、int、char类型,简单讲它们转为int,这些类型中的任何一个不同的搜索键将有不同的散列吗。
对于float,使用Float.floatToIntBits(key)作为散列码,方法返回一个int值。该值得比特表示和浮点数f的比特表示相同。

对于long类型的搜索键,简单地转为int不是很好的选择,因为无法反应前面32高位的不同。考虑到这种情况,将64比特分为两部分,并执行异或操作将两部分结合,这个过程称为折叠(folding)。
一个long类型键的散列码为:

int hashCode=(int)(key^(key>>32));

对于double类型的搜索键,首先使用Double.doubleToLongBits方法转为long值,再执行折叠操作。

4.字符串类型的散列码
一个比较直观的方法是将所有字符的unicode求和作为字符串的散列码。这个方法可能有较大的冲突,也无法区分dog与dgo。
一个更好的方法是考虑字符的位置,然后产生散列码:

这里Si为s.charAt(i),这个方法被称为多项式散列码。计算时,对于长的字符串会导致溢出,但Java中会忽略溢出。要最小化冲突,关键是选择合适的b,实验显示,b较好的取值为31,33,37,39,41。

java.lang.String.java中的多项式散列实现:

/*** Returns a hash code for this string. The hash code for a* {@code String} object is computed as* <blockquote><pre>* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]* </pre></blockquote>* using {@code int} arithmetic, where {@code s[i]} is the* <i>i</i>th character of the string, {@code n} is the length of* the string, and {@code ^} indicates exponentiation.* (The hash value of the empty string is zero.)** @return  a hash code value for this object.*/public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}

5.压缩散列码
键的散列码可能是一个很大的整数,超过了散列表索引的范围,因此需要将它缩小。假设散列表的索引处于0到N-1之间,常用的压缩做法是:
h(hashCode)=hashCode%N

保证索引均匀扩展,选择N大于2的素数。

上面的式子等价于:
h(hashCode)=hashCode&(N-1)

为保证散列是均匀分布的,java.util.HashMap的实现中采用了补充的散列函数与主散列函数一起使用:

private static int supplementalHash(int h){h^=(h>>>20)^(h>>>12);return h^(h>>>7)^(h>>>4);
}

完整的散列函数:

h(hashCode)= supplementalHash(hashCode)%N

这个式子与下面式子一样:

h(hashCode)= supplementalHash(hashCode) &(N-1)

 

三. 开放地址法

当两个键映射到散列表中的同一个索引,冲突发送,通常有2种方法处理冲突:开放地址法与链地址法

开放地址法有以下几个变体。
1.线性探测
线性探测法在发生冲突时,按顺序找到下一个可用的位置。连续冲突时继续按序检查,直到找到可用位置。
当探测到表的终点时,则返回表的起点。因此,散列表被当成是循环的。

线性探测法容易导致散列表中连续的单元组被占用。这样的每个组称为一个簇(cluster)。

2.二次探测
线性探测法从索引k的位置检查连续单元,二次探测法则从索引为(k+j^2)%N位置开始检查,其中j>=0。

二次探测法避免了线性的成簇问题,但有自己本身的成簇问题,称为二次成簇,即产生冲突的条目将采用同样的探测序列。

3.再哈希法
避免成簇问题的另一个方法是再哈希法。

 

 

四. 链地址法
链地址法将具有相同的散列索引的条目都放在一个位置,每个位置使用一个桶来放置这些条目。

 

链地址法是种广泛使用的方法。
(在JDK中有不少基于此方法的实现,如jdk1.7的hasMap实现方案,在多线程环境中发生链循环等错误,jdk1.8中重写了链的处理,修正了此错误等故事。)

 

五. 装填因子和再散列
装填因子(load factor)衡量一个散列表有多满。如果装填因子超出,则增加散列表的大小,并重新装载条目到一个新的更大的散列表中,这称为再散列。
装填因子=条目数n/容量N,如果散列表满了,装填因子=1
当装填因子接近1时,冲突的可能性就增大。一般对于开发地址法,装填因子需要控制在0.5下,链地址法通常维持在0.9下。

在java.util.HashMap的实现中,采用了装填因子0.75的阈值。一旦超过阈值,就需要增加散列表的大小,并进行再散列。再散列的代价比较大,为避免频繁的再散列,一旦扩容时应该至少将散列表的大小翻倍。

/*** The maximum capacity, used if a higher value is implicitly specified* by either of the constructors with arguments.* MUST be a power of two <= 1<<30.*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** The load factor used when none specified in constructor.*/static final float DEFAULT_LOAD_FACTOR = 0.75f;

 

转载于:https://www.cnblogs.com/GGGong/p/11048259.html

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

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

相关文章

移动端触摸(touch)事件

目有个交互需要实现手指滑动的交互&#xff0c;pc端使用mousedown,mousemove,mouseup监听实现。 但在ios设备上mousemove是不好监听的&#xff0c;同类的方法是touchstart,touchmove,touchend。 项目需求&#xff0c;需要用到拖动事件。由于不需要考虑IE8等低端浏览器的兼容性&…

numcpp速度对比_PHP和C++性能对比.pdf

PHP 与C性能比较本文博客链接&#xff1a;http://keping.me/php_vs_cpp/PHP 是速度很快的脚本语言&#xff0c;但是用了框架以后好像感觉挺慢的。于是猜测会不会PHP 本身也不是很快。如果不是很快&#xff0c;能否采用 PHP 调用本地动态链接库的形式来提升速度。于是有了下面的…

jndi ldap_什么是JNDI,SPI,CCI,LDAP和JCA?

jndi ldapJNDI代表Java命名和目录接口 。 它是用于提供对目录服务&#xff08;即&#xff0c;服务映射名称&#xff08;字符串&#xff09;与对象&#xff0c;对远程对象或简单数据的引用&#xff09;访问的API。 这就是所谓的 约束力 。 绑定集称为上下文 。 应用程序使用JND…

PyOpenCV 基本操作

目录 1. 图片加载、显示和保存 2. 图像显示窗口创建与销毁 3. 图片宽、高、通道数获取 4. 图像像素数目和图像数据类型的获取 5. 生成指定大小的空图像, 生成指定大小的空图像 6. 访问和操作图像像素 7. 图像三通道分离和合并 8. 抓取摄像头 1. 图片加载、显示和保存 …

python中用于标识字符串的定界符_Python 基本数据类型

######################基本数据类型######################数字类型整数 int整数是用来表示整数数值,即没有小数部分的数值,包括正整数 负整数和0整数类型包括十进制整数 八进制整数 十六进制整数和二进制整数例如: 0 , 100 , 65205浮点数 float浮点数由整数部分和小数部分组成…

适用于Java开发人员的Elasticsearch:命令行中的Elasticsearch

本文是我们学院课程的一部分&#xff0c;该课程的标题为Java开发人员的Elasticsearch教程 。 在本课程中&#xff0c;我们提供了一系列教程&#xff0c;以便您可以开发自己的基于Elasticsearch的应用程序。 我们涵盖了从安装和操作到Java API集成和报告的广泛主题。 通过我们简…

系统间账号认证系统同步方案

系统间账号认证系统同步方案 基础原理&#xff1a;(基于Web) 浏览器在个请求传递cookie到服务器&#xff0c;服务器对cookie增删改查的操作, 写入JSessionId实现与服务器Session的绑定&#xff0c;保持会话 单机情况下&#xff1a;一个域名&#xff0c;对应一个cookie&#xff…

Pytorch 加载预训练模型参数时出现size mismatch错误

目录 1 不妨先研究一下’ resnet18-5c106cde.pth’里面存了什么东西以及它的数据类型 (1_1)’ resnet18-5c106cde.pth’的数据类型

python元类单例_python面向对象和元类的理解

1 python类对象与实例对象python中一切皆对象(广义上的对象)&#xff0c;类也不例外&#xff0c;我们可以称类为类对象。python中内建函数type()可以返回对象的类型&#xff0c;例如type(int)会得到返回值&#xff0c;而int为类型工厂函数&#xff0c;是内置的类对象。如果对自…

Java命令行界面(第7部分):JCommander

这是我系列的第七篇文章&#xff0c;简要介绍了用于处理Java命令行参数的各种库。 这篇文章回到了基于注释的库的覆盖范围&#xff0c;该库似乎是在Java中可用于处理命令行参数的众多可用库中知名度最高和最受欢迎的库之一&#xff1a; JCommander 。 JCommander的网页上指出&…

Pytorch 加载部分预训练模型并冻结某些层

目录 1 pytorch的版本&#xff1a; 2 数据下载地址&#xff1a; 3 原始版本代码下载&#xff1a; 4 直接上代码&#xff1a; 1 pytorch的版本&#xff1a; 2 数据下载地址&#xff1a; <https://download.pytorch.org/tutorial/hymenoptera_data.zip> 3 原始…

INT类型知多少

前言&#xff1a; 整型是MySQL中最常用的字段类型之一&#xff0c;通常用于存储整数&#xff0c;其中int是整型中最常用的&#xff0c;对于int类型你是否真正了解呢&#xff1f;本文会带你熟悉int类型相关知识&#xff0c;也会介绍其他整型字段的使用。 1.整型分类及存储范围 整…

altera fpga 型号说明_A/X家FPGA架构及资源评估

欢迎FPGA工程师加入官方微信技术群点击蓝字关注我们FPGA之家-中国最好最大的FPGA纯工程师社群评估对比xilinx以及altera两家FPGA芯片逻辑资源。首先要说明&#xff0c;现今FPGA除了常规逻辑资源&#xff0c;还具有很多其他片内资源比如块RAM、DSP单元、高速串行收发器、PLL、AD…

guava api_使用Google Guava的订购API

guava api我们在Google的Guava库中玩的更多&#xff0c;这真是一个了不起的库&#xff01; 我们用于它的最新内容是为我们的域对象整理比较器。 这是如何做。 使用Apache Isis的JDO Objectstore &#xff0c;使您的类实现java.lang.Comparable &#xff0c;并对集合使用SortedS…

Pytorch 加载和保存模型

目录 保存和加载模型 1. 什么是状态字典&#xff1a;state_dict? 2.保存和加载推理模型 2.1 保存/加载 state_dict &#xff08;推荐使用&#xff09; 2.2 保存/加载完整模型 3. 保存和加载 Checkpoint 用于推理/继续训练 4. 在一个文件中保存多个模型 5. 使用在不同…

02-CSS基础与进阶-day9_2018-09-12-20-29-40

定位 静态定位 position: static 相对定位 position: relative 绝对定位 position: absolute 脱标 参考点 子绝父相 让绝对定位的盒子水平居中和垂直居中 固定定位 position: fixed 参考点 浏览器左上角 固定定位的元素脱标不占有位置 兼容性 ie6低版本不支持固定定位 02绝对…

activity直接销毁_Android -- Activity的销毁和重建

两种销毁第一种是正常的销毁&#xff0c;比如用户按下Back按钮或者是activity自己调用了finish()方法&#xff1b;另一种是由于activity处于stopped状态&#xff0c;并且它长期未被使用&#xff0c;或者前台的activity需要更多的资源&#xff0c;这些情况下系统就会关闭后台的进…

Storm和Kafka集成的重要生产错误和修复

我将在此处描述Storm和Kafka集成模块的一些细节&#xff0c;一些您应该意识到的重要错误以及如何克服其中的一些错误&#xff08;尤其是对于生产安装&#xff09;。 我在生产安装中大量使用Apache Storm&#xff0c;并将Kafka作为主要输入源&#xff08;Spout&#xff09;。 …

博客园背景设置CSS代码

/配色参考->>->>>//https://zh.spycolor.com/color-index,a*/ #home { margin: 0 auto; width: 90%;/原始65/ min-width: 980px;/页面顶部的宽度/ background-color:rgba(233,214,107,0.3);/博客主页主体框的颜色/ padding: 30px; margin-top: 25px; margin-bot…

matplotlib 画多条折线图且x轴下标非数值

直接上python代码&#xff1a; # -*- coding: utf-8 -*- import matplotlib.pyplot as plt names [GFK, SA, DA-NBNN, DLID, DaNN, Ours] x range(len(names))y_1 [0.464, 0.45, 0.528, 0.519, 0.536, 0.841] y_2 [0.613, 0.648, 0.766, 0.782, 0.712, 0.954] y_3 [0.663…