算法与数据结构-Hash表的理解

序言

上次美团电话面试,面试官问了解hash表吗?可惜平时没有好好看过hash表的东西,根本回答不上来。
准备学习一下Hash表的概念和实现。

  • 哈希表-Hash Table又称散列表

    • 是根据关键码值而直接进行访问的数据结构。

    • 散列表算法在查找时不需要进行一系列和关键字(关键字是数据元素中某个数据项的值,用以标识一个数据元素)的比较操作。

    • 散列表算法希望能尽量做到不经过任何比较,通过一次存取就能得到所查找的数据元素,因而必须要在数据元素的存储位置和它的关键字(可用key表示)之间建立一个确定的对应关系,使每个关键字和散列表中一个唯一的存储位置相对应。因此在查找时,只要根据这个对应关系找到给定关键字在散列表中的位置即可。这种对应关系被称为散列函数(可用h(key)表示)。

    • 可将其抽象为“数组 + 链表”的复合结构。

  • 哈希表的实现

    • 有多种实现方法,最常用的是拉链法-链表的数组

    • 建立一个数组,数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去。也是根据这些特征,找到正确的链表,再从链表中找出这个元素

  • 数组和链表的特点

    • 数组:寻址容易,插入和删除困难
    • 链表:插入和删除容易,寻址困难
  • 哈希表为什么能提高查找速度

    • [1] 哈希函数建立了数据存储位置和数据记录的内容的关联
    • [2] 采用了数组“快速访问”的特点,利用哈希函数对关键码值进行转换并快速定位,不需要像链表那样从头节点开始一个个遍历去查
  • 哈希函数-Hash Function,又名散列函数,一般来说散列函数满足以下两个条件+两个附加条件

    • [1] 对输入值运算,得到一个固定长度的摘要(Hash value)

    • [2] 不同的输入值可能对应不同的输出值

    • (1) 散列函数的输出值尽量接近均匀分布

    • (2) x的微小变化可以使f(x)发生非常大的变化,即所谓“雪崩效应”

  • 常用的Hash函数构造方法

    • 直接定址法:

      • 取关键字或关键字的某个线性函数值为散列地址,即: h(key) = key 或 h(key) = a * key + b,其中a和b为常数。
    • 数字分析法

    • 平方取值法

      • 取关键字平方后的中间几位为散列地址:如index = (key * key) >> 28
    • 折叠法
      • 将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址。
    • 除留余数法
      • 取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址:index = key % 16
      • h(key) = key MOD p p ≤ m
    • 随机数法
      • 选择一个随机函数,取关键字的随机函数值为它的散列地址,即:h(key) = random(key),其中random为随机函数。

    比较常用的是:除留余数法 + 平方散列法 + Fabonacci散列法(平方散列法的改进)

    Fabonacci散列法:index = (key * 2654435769) >> 28
    [1] 对于16位整数而言,这个乘数是40503
    [2] 对于32位整数而言,这个乘数是2654435769
    [3] 对于64位整数而言,这个乘数是11400714819323198485

  • 哈希冲突

    • 哈希函数是一个多对一函数,如果记录Hash值的范围多于Hash表的条数,不可避免的会发生冲突
  • 哈希冲突的解决方案

    • [1] 对Hash表中每个Hash值建立一个冲突表,即将冲突的几个记录以表的形式存储在其中;

    • [2] 改变规则重新计算一次Hash值;

    • [3] 建立一个公用区域存放冲突的表项;

    在工程上,考虑到实现算法的复杂度,方法1用得是最多的

  • Hash的基本思路说明

现有4个元素要存储 13 7 14 11

用数组来存储是: a[0] = 13, a[1] = 7, a[2] = 14, a[3] = 11

Hash存储过程如下:

    1. 先确定Hash函数,假如使用 h(key) = key % 5

    2. 映射并存储
        四个元素分别得到 h(13) = 3, h(7) = 2, h(14) = 4, h(11) = 1,
        此时对应存储为 Hash[3] = 13Hash[2] = 7, Hash[4] = 14, Hash[1] = 11
    3. Hash查找
        对于数组,要找一个元素,顺序查找一遍对比是否是要找的元素,比如查找11,需要查找4次
        对于Hash表,先做hash映射h(11) = 1,然后查看Hash[1] ?= 11即可,只找了一次



Acknowledgements:
http://blog.csdn.net/u013630349/article/details/47856815
http://blog.csdn.net/songzi1111/article/details/10985429
http://blog.csdn.net/v_JULY_v/article/details/6256463

2017.09.20

你可能感兴趣的:(算法与数据结构)