数据结构_散列表查找(哈希表)概述

目录

散列表查找(哈希表)概述

散列表查找定义

散列表查找步骤

散列函数的构造方法

直接定址法

数字分析法

平方取中法

折叠法

除留余数法

随机数法

总结

处理散列冲突的方法

开放定址法

再散列函数法

链地址法

公共溢出区法

散列表查找实现

散列表查找性能分析


​​​​​​​

散列表查找(哈希表)概述

散列表查找定义

我们可以通过查找关键字不需要比较就可获得需要的记录的存储位置。这就是一种新的存储技术——散列技术。

  • 存储位置 = f  ( 关键字 )

散列技术:散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系 f ,使得每个关键字 key 对应一个存储位置 f ( key ) 。查找时,根据这个确定的对应关系找到给定值 key 的映射 f ( key ) ,若查找集合中存在这个记录,则必定在 f ( key ) 的位置上。

这里我们把这种对应关系 f 称为 散列函数 ,又称为 哈希 ( Hash ) 函数。按照这个思想,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为 散列表哈希表 ( Hash table ) 。那么关键字对应的记录存储位置我们称为 散列地址

散列表查找步骤

  1. 在存储中,通过散列函数计算记录的散列地址,并按此散列地址存储该记录。无论记录什么,我们都需要用同一个散列函数计算出地址再存储。
  2. 当查找记录时,我们通过同样的散列函数计算计算记录的散列地址,按此散列地址访问该记录。

散列技术既是一种 存储方法 ,也是一种 查找方法 。然而它与线性表、树、图等结构不同的是,前面几种结构,数据元素之间都存在某种逻辑关系,可以用连线图示表示出来,而散列技术的记录之间不存在什么逻辑关系,它只与关键字有关连。因此,散列主要是面向查找的存储结构。

散列技术最适合的求解问题是查找与给定值相等的记录。对于查找来说,简化了比较的过程,效率就会大大提高。但万事有利就有弊,散列技术不具备很多常规数据结构的能力。

冲突:我们时常会碰到两个关键字 key₁ ≠ key₂ ,但是却有 f( key₁ ) 不等于 f( key₂ ) ,这种现象我们称为 冲突 ( collision ) ,并把 key₁ 和 key₂ 称为这个散列函数的同义词 ( synonym ) 。

散列函数的构造方法

什么才算是好的散列函数:

  1. 计算简单
  2. 散列地址均匀分布

直接定址法

我们可以取关键字的某个线性函数值为散列地址

  • f ( key ) = a × key + b    ( a、b 为常数 )

数字分析法

数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀就可以考虑用这个方法。

平方取中法

假设关键字是1234,那么它的平方就是1522756,再抽取中间的 3 位就是 227 ,用作散列地址。平方取中法比较适用于不知道关键字分布,而位数又不是很大的情况。

折叠法

折叠法是将关键字从左到右分割成位数相等的几部分(注意最后一部分位数不够时可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。

比如我们的关键字是 9876543210 ,散列表表长位三位,我们将它分为四组,987|654|321|0,然后将它们叠加求和 987+654+321+0=1962,再求后 3 位得到散列地址为 962 。

折叠法事先不需要知道关键字的分布,适合关键字位数较多的情况。

除留余数法

此方法为最常用的构造散列函数的方法。对于散列表长为 m 的散列函数公式为:

  • f ( key ) = key mod p ( p ≤  m )

mod 是取模(求余数)。事实上,这方法不仅可以对关键字直接取模,也可以在折叠、平方取中后再取模。

随机数法

选择一个随机数,取关键字的随机函数值为它的散列地址。也就是 f ( key ) = random ( key ) 。这里的 random 是随机函数。当关键字的长度不等时,采用这个方法构造散列函数是比较合适的。

总结

现实中,应该视不同的情况采用不同的散列函数。可以根据一些考虑的因素来提供参考:

  • 计算散列地址所需的时间
  • 关键字的长度
  • 散列表的大小
  • 关键字的分布情况
  • 记录查找的频率

处理散列冲突的方法

开放定址法

开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。

  • fᵢ ( key ) = ( f ( key ) + dᵢ ) MOD m   ( dᵢ = 1,2,3, … , m-1 )

我们把这种解决冲突的开放定址法称为线性探测法。

冲突:我们把本来不是 同义词却需要争夺一个地址的情况,我们称这种现象为 堆积

再散列函数法

对于散列表来说,我们事先准备多个散列函数,RHᵢ 是不同的散列函数。

fᵢ ( key ) = RHᵢ ( key )   ( i = 1,2,3, … , k )

链地址法

将所有的关键字为同义词的记录存储在一个单链表中,我们称这种表为同义词子表,在散列表中只存储所有的同义词子表的头指针。

公共溢出区法

为所有冲突的关键字建立了一个 公共的溢出区来存放。在查找时,对给定值通过散列函数计算出散列地址后,先与基本表的对应位置进行比对,如果相等则查找成功;如果不相等,则溢出表去进行顺序查找。如果相对于基本表而言,有冲突的数据很少的情况下,公共溢出区的结构对查找性能来说还是非常高的。

散列表查找实现

散列表查找性能分析

  1. 散列表是否均匀
  2. 处理冲突的方法
  3. 散列表的填装因子

猜你喜欢

转载自blog.csdn.net/ashmoc/article/details/120265653