• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > Java数据结构之散列表(动力节点Java学院整理)

Java数据结构之散列表(动力节点Java学院整理)

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了动力节点java视频,java动力节点,动力节点java官网,动力节点java视频下载,北京动力节点java培训等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

基本概念

散列表(Hash table,也叫哈希表),是根据关键字(key value)而直接进行访问的数据结构。

说的具体点就是它通过吧key值映射到表中的一个位置来访问记录,从而加快查找的速度。

实现key值映射的函数就叫做散列函数

存放记录的数组就就叫做散列表

实现散列表的过程通常就称为散列(hashing),也就是常说的hash

散列

这里的散列的概念不仅限于数据结构了,在计算机科学领域中,散列-哈希是一种对信息的处理方法,通过某种特定的函数/算法(散列函数/hash()方法)将要检索的项与用来检索的索引--( 散列值)关联起来,生成一种便于搜索的数据结构--散列表。如今,由于散列算法所计算的散列值 具有不可逆(无法逆向演算会原来的数值)的性质,因此散列算法广泛的运用于加密技术。

散列的运用:

1、加密散列,在信息安全领域使用

2、散列表,一种使用散列函数将键名和键值关联起来的数据结构

3、关联数组,一种常常使用散列表来实现的数据结构

4、几何散列,寻找相同或相似的几何形状的一种有效方法

散列函数

通过上面可以知道,散列技术的实现是基于散列函数的。这里对散列函数进行一个较深入的理解。前面就知道了散列函数--哈希函数就是完成key值与位置的映射。一般说来key以字符 串的形式居多,位置也就是一个数值。可以看出散列函数就像是实现信息的压缩,把消息字符 串压缩成数值摘要,是数据量变小,格式得以固定下来。
散列函数的工作原理图:

不过需要注意的是key值和经过散列函数处理之后的散列值并不是唯一对应的,这就造成了不同的key值具有相同的索引位置,这种现象叫做散列碰撞、也称其为哈希冲突。对于hash冲突的解决办法,将在后面予以总结。至于散列函数的具体实现,有很多加密技术都有十分nice的实现,这里我们看看Java中HashMap的hash()方法实现就可以了。HashMap采用的是内部哈希技术实现的,其中hash()方法就是散列函数,完成key值到数组索引位置的映射。                   

 /** 
  * Retrieve object hash code and applies a supplemental hash function to the 
  * result hash, which defends against poor quality hash functions. This is 
  * critical because HashMap uses power-of-two length hash tables, that 
  * otherwise encounter collisions for hashCodes that do not differ 
  * in lower bits. Note: Null keys always map to hash 0, thus index 0. 
  */ 
 final int hash(Object k) { 
  int h = 0; 
  if (useAltHashing) { 
   if (k instanceof String) { 
    return sun.misc.Hashing.stringHash32((String) k); 
   } 
   h = hashSeed; 
  } 
  h ^= k.hashCode(); 
  // This function ensures that hashCodes that differ only by 
  // constant multiples at each bit position have a bounded 
  // number of collisions (approximately 8 at default load factor). 
  h ^= (h >>> 20) ^ (h >>> 12); 
  return h ^ (h >>> 7) ^ (h >>> 4); 
 } 
</div>

上述代码就是HashMap中散列函数的具体实现。JDK1.7这里笔者对常用的散列算法做一个展示:

散列表

在理解了上述散列\散列函数的概念之后我们正式的进入到散列表的学习.一个通俗的例子是,为了查找电话簿中某人的号码,可以创建一个按照人名首字母顺序排列的表(即建立人名 x 到首字母 F(x) 的一个函数关系),在首字母为 W 的表中查找“王”姓的电话号码,显然比直接查找就要快得多。这里使用人名作为关键字,“取首字母”是这个例子中散列函数的函数法则 F(),存放首字母的表对应散列表。关键字和函数法则理论上可以任意确定。

散列函数的构造

对于散列表这种数据结构来说,其散列函数的构造是十分关键的,散列函数实现了key的映射,并且访问记录可以更快的被定位。一般来说散列函数的构造基于两个标准:简单、均匀简单指散列算法简单快捷,散列值生成简单。均匀指对于key值集合中的任一关键字,散列函数能够以均与的概率映射到数组的任一一个索引位置上,这样能够减少散列碰撞。
散列函数构造方法:

1、直接地址法:

直接取key值或者key值的某个线性函数值作为散列地址。即hash(k)=k或者hash(k)=a*k+b。

Tips: 简单的思考一下这种方式就可以知道,这种方式基本不会存在哈希冲突,不过事先我们应该知道key集合的大小,而且使用线性函数值作为散列地址的话,很大程度上造成了空间的浪费。hash(k)=k这种方式更加的鸡肋没必要,以这种方式散列还不如直接数组索引。

2、数字分析法:

所谓的数字分析法就是假设关键字key是以r为基的数,并且hash表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成hash地址。

Tips:这种方式极度不灵活,限制太多。

3、平方取中法:

先通过求关键字的平方值扩大相近数的差别,然后根据表长度取中间的几位数作为散列函数值。

Tips:这种方式中间的几位数都和关键字的没一位都有关,产生的散列地址较为的均匀。

4、折叠法:

将关键字分割成相同的几位数(最后一位可不同),然后去这几部分的叠加和。折叠法一般是和除留余法一起使用的。

5、除留余法:

取关键字被某个不大于散列表表长 m 的数 p 除后所得的余数为散列地址。即 hash(k)= k mod p, p < m。不仅可以对关键字直接取模,也可在折叠法、平方取中法等运算之后取模。对 p 的选择很重要,一般取素数或 m ,若 p 选择不好,容易产生碰撞。

6、随机法:

h(key)=random(key)    其中random为伪随机函数,但要保证函数值是在0到m-1之间。总结:在上述的方法中,3、4、5三种方法的结合使用方式较好,在JDK以前的版本就是使用的方法5。

哈希冲突

通过上面的学习中,我们知道散列函数得到的key -  索引位置 并不是唯一对应的,可能造成不同的key值对应相同的索引位置。这是我们应该解决的问题。实际的解决方法一般如下:

1、分离连接法:

首先看看分离连接法,说白了这种方式就是链表数组的方式,将散列到同一个值得所有元素保存在一个表中,产生相同的一个值在散列表中使用链表的形式存储。哈希冲突的位置就是链表的开始位置。在JKD中HashMap就是这种方式解决哈希冲突的!

HashMap中冲突处理代码如下   

for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
   Object k; 
   if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
    V oldValue = e.value; 
    e.value = value; 
    e.recordAccess(this); 
    return oldValue; 
   } 
  } 
</div>

2、开放地址法

分离连接法的缺点在于使用了链表,由于给新的单元分配地址耗费时间,造成算法速度较慢,解决的方法就是开放地址法,在开放地址法中较为常用的有两种:线性探测法、平方探测法。 
开放地址法:    

hash_i=(hash(key) + d(i)) mod m, i=1,2...k\,(k < m-1),其中hash(key)为散列函数,m为散列表长,d(i)为增量序列,i为已发生碰撞的次数。增量序列可有下列取法:

d(i)=1,2,3...(m-1) 称为 线性探测;即 d(i)=i ,或者为其他线性函数。相当于逐个探测存放地址的表,直到查找到一个空单元,把散列地址存放在该空单元。d(i)=1^2,  2^2,3^2... k^2 (k < m/2) 称为 平方探测。相对线性探测,相当于发生碰撞时探测间隔 d(i)=i^2 个单元的位置是否为空,如果为空,将地址存放进去。d(i)=伪随机数序列,称为 伪随机探测。

线性探测法

下面笔者将以一个实例演示线性探测的过程,进而分析线性探测的特点,引出平方探测关键字为{89,18,49,58,69}插入到一个散列表中的情况。此时线性探测的方法是取d(i)=i。并假定取关键字除以 10 的余数为散列函数法则。

1、开始时hash(89)=9无冲突,直接插入;

2、hash(18)=8无冲突,直接插入;

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Java 可视化垃圾回收_动力节点Java学院整理
  • Java中的FilterOutputStream 简介_动力节点Java学院整理
  • Java装饰器设计模式_动力节点Java学院整理
  • Java中的 FilterInputStream简介_动力节点Java学院整理
  • ByteArrayOutputStream简介和使用_动力节点Java学院整理
  • Java自定义异常_动力节点Java学院整理
  • Java异常继承结构解析_动力节点Java学院整理
  • Java枚举_动力节点Java学院整理
  • Java数据结构之图(动力节点Java学院整理)
  • Java数据结构之散列表(动力节点Java学院整理)

相关文章

  • 2017-05-28Java 7大常见排序方法实例详解
  • 2017-05-28Java中Builder模式的实现详解
  • 2017-05-28Java多线程中线程间的通信实例详解
  • 2017-05-28Java 中HashCode作用_动力节点Java学院整理
  • 2017-05-28浅谈java中的对象、类、与方法的重载
  • 2017-05-28Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例
  • 2017-05-28Spring Boot + Jpa(Hibernate) 架构基本配置详解
  • 2017-05-28spring整合redis缓存并以注解(@Cacheable、@CachePut、@CacheEvict)形式使用
  • 2017-05-28详解Spring简单容器中的Bean基本加载过程
  • 2017-05-28Java正则判断日期格式是否正确的方法示例

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
    • Java微信公众平台开发(8) 多媒体消息回复
    • spring boot装载自定义yml文件
    • java+jsp+struts2实现发送邮件功能
    • java判断今天,昨天,前天,不能用秒间隔的简单实例
    • Java 队列 Queue 用法实例详解
    • Java多线程并发编程 Synchronized关键字
    • Java编程实现中英混合字符串数组按首字母排序的方法
    • java 同步器SynchronousQueue详解及实例
    • 详解Spring Boot 使用slf4j+logback记录日志配置

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有