数据结构——hash函数、散列表

散列表(hash表):是根据关键码值而直接进行访问的数据结构

在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每一个关键字和结构中唯一的存储位置相对应。称这个对应关系f为哈希(hash)函数,按这个思想建立的表为哈希表若关键字为k,则其值存放在f(k)的存储位置上。

对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),这种现象称为冲突。具有相同函数值的关键字对于该哈希函数来说称作同义词。(此处,k1,k2互为同义词)

根据散列函数f(k)处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字k在地址集中的“像”f(k)作为记录在表中的存储位置,这种表便称为散列表,所得的存储位置称散列地址

实际工作中需视不同的情况采用不同的哈希函数和不同的处理碰撞冲突的方法。

常用的hash函数:

  • 直接地址法
  • 数字分析法
  • 平方取中法
  • 折叠法
  • 除留余数法(H\left ( key \right )=key MOD\displaystyle p,p\leq M,选p为素数或小于20的质因数的和数,eg:3,5,7,15,23.....)
  • 随机法

散列函数和键的类型有关,eg:如果键是一个数字, 我们可以直接使用这个数字;如果键是一个字符串,就需要将这个字符串转化为一个数字;如果键包含多个部分(比如email地址),就需要某种方法将这些部分结合起来。 

构造hash函数 需要考虑的因素有:

  • 计算hash函数所需时间;
  • 关键字的长度;
  • hash表的大小;
  • 关键字的分布情况;
  • 记录的查找频率。

对于长度为M的表,必须满足\forall k,f(k)\sqsubseteq (0,M-1),即任何关键字所得的存储位置必须落在表长允许范围内。

常用处理冲突的方法:

  • 开放地址法(依靠数组中的空位解决碰撞冲突,要求数组长度M〉键值对个数N)
  • 再哈希法
  • 链地址法 (将所有关键字为同义词的记录存储在同一线性链表中)。最常用
  •  建立一个公共溢出区

数据结构——hash函数、散列表_第1张图片

 数据结构——hash函数、散列表_第2张图片图中,紫色部分即代表哈希表,也称为哈希数组,数组的每个元素都是一个单链表的头节点,链表是用来解决冲突的,如果不同的key映射到了数组的同一位置处,就将其放入单链表中。

 

  java中的HashMap的底层主要就是基于数组和链表来实现的,HashMap底层是通过链表来解决hash冲突的。

你可能感兴趣的:(数据结构——hash函数、散列表)