散列表(哈希表)查找

本文详细介绍了散列技术,包括散列表查找步骤、散列函数的构造方法及其特点。讨论了处理冲突的多种方法,如开放地址法、再散列函数法和链地址法,并提供了Java程序实现示例。通过理解这些概念,读者可以更好地掌握散列在查找和存储中的应用。
摘要由CSDN通过智能技术生成

概述

散列技术: 存储位置=f(key)
在记录的存储位置和它的关键字之间建立一种确定的关系F,使得每一个关键字key都有一个存储位置F(key)。
这个关系f称为散列函数,又称为哈希(hash)函数。
散列表:
采用散列技术将记录存储在一块连续的存储空间中,这块连续的存储空间就称为散列表或者哈希表(hash table)。


散列表查找步骤

  1. 在存储时,通过散列函数计算散列地址,并在散列地址存储记录。
  2. 查找记录时,通过同样的散列函数计算散列地址,并按散列地址访问该记录。
    所以,散列技术即是一种存储方法,也是一种查找方法。

散列表的特点

  1. 散列技术最适合求解问题是查找与给定值相等的记录。
  2. 散列技术的记录之间没有什么逻辑关系。
  3. 同样的关键字,能对应很多个记录的情况不适合散列技术
  4. 表中的记录不能排序,像最大值、最小值等结果也无法从散列表中计算出来
  5. 经常会有冲突现象
    note :冲突(collision):两个关键字key1 != key2,却有f(key1) = f(key2),这种现象为冲突。把key1 和key2 称为这个函数的同义词(synonym)。
    如何处理冲突时一个很重要的课题。

散列函数的构造方法

一个好的散列函数的,两个常见原则。
1. 计算简单。(散列函数的计算时间不应该超过其他查找技术与关键字比较的时间)
2. 散列地址分配均匀。(保证存储空间的有效利用,减少处理冲突而耗费时间)

直接定址法

取关键字的某个线性函数作为散列函数 ,即f(key) = a*key +b。
优点:
  简单,均匀,也不会产生冲突。
缺点:
   需要事先知道关键字的分布,适合查找表较小且连续的情况。
note:这个方法并不常用

数字分析法

  抽取关键字的一部分来作为散列存储位置,或者抽取出来后在翻转,反转,移位,叠加。总之就是为了让关键字均匀的分布到散列表中。
  这种抽取的方法是散列函数中常用的方法。
  特点:
   适合处理关键字比较大的情况,如果事先知道关键字本身的结构分布,且关键字的若干位分布比较均匀,就可以考虑这个方法。

平方取中法

  先对关键字平方,在取其中间部分。
  特点:
  适合不知道关键字分布,为位数又不是很大的情况。

折叠法

  将关键字从左到右分割成位数相等的几部分(最后一个位数不够可以短一些)然后这几部分求和,并按散列表表长,去最后几位作为散列地址。
  特点:
  事先不知道关键字的分布,适合关键字位数较多的情况。

除留余数法

  最常见的散列构造函数,对于散列表长为m的散列函数为
   f(key) = key mod p (p<=m)
  note: 根据经验,若散列表长为m,通常p为小于或等于表长(最好是接近m)的最小质数,或者不包括小于20的质因子的合数。

随机数法

  取关键字的随机函数值作为它的散列地址。也就是f(key) = random(key)。random是随机函数。
  特点:
  当关键字的长度不等时,采用这个方法构造散列函数是比较合适的。
note:如果关键字是字符串,就转换为某种数字来对待,比如ASCII或者unicode码等。

总结

实际运用中,根据不同情况采取不同的散列函数,这里有一因数来提供综合考虑。
1. 计算散列地址所需时间
2. 关键字的长度
3. 散列表的大小
4. 关键字的分布情况
5. 记录查找的频率。


处理散列冲突的方法

冲突有时候很难避免,所以要研究如何处理。
实在追不到梦中情人就换一个呗——开放地址法,或者去别的地方再找—再散列函数法。

开放地址法

  开放地址法:一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,总可以找到空的地址,并将记录存进去。
  它的公式:f(key) = (f(key)+d) mod m (d = 1,2,3 ,,,m-1)
  f(key) 是除留余数法,折叠法等。
  这种解决冲突的开放定址法也称为线性探测法。
堆积:
  本来不是一个同义词却要争夺一个地址的现象。
  二次试探法:
f(key)=(f(key)+d) mod m(d = 1^2,-1^2,2^2,-2^2, .. ,q^2,-q^2;q<=m/2)
  增加平方算子的目的是为了不让关键字都聚集在某一块区域。
  随机试探法:
  在冲突时,如果位移量d采用随机数函数计算得到,称之为随机试探法。当然这里的随机函数是伪随机。在查找时设置相同的随机种子,不断调用随机函数就可以生成同一个不重复的数列。
  这是解决冲突的常用方法

再散列函数法

  冲突时重新选择散列函数
  f(key) = RHi(key) (i=1,2,3 … ,k)
  RHi就是不同的散列函数,总有一个函数可以把冲突解决
  特点:
  关键字不产生聚集,当然,相应的也增加了计算时间。

链地址法

  冲突也不换地方
  将所有关键字为同义词的记录存储在一个单链表中,我们称这种表为同义词子表。在散列表中值存储所有同义词字表的的头指针。
  特点:
  绝对不会出现找不到地址,当然也带来了查找时需要遍历单链表的性能损耗。

公共溢出区

  我们为所以冲突的关键字建立一个公共的溢出区来存放记录。
  特点:
  在冲突数据较少的情况下,公用溢出区的结构对查找性能还是非常高的。


java程序实现

采用线性试探法解决冲突的散列查找实现
    /*****************************
     * 散列表查找技术
     * ****************************/

    /*散列表结构类
     * 采用线性试探法解决冲突,元素被删除后,存储位置也删除就会割断查找后边元素的路径
     * */
public class HashTable {
   
    private Object [] key;//b保存元素关键字数组
    private Object [] ht;//散列表
    private int count;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值