• 哈希表的概念和简单的实现算法


    整理了一下Hash表相关内容,如下:
    Hash 表是使用 O(1) 时间进行数据的插入删除和查找的表,但是 hash 表不保证表中数据的有序性,这样在 hash 表中查找最大数据或者最小数据的时间是 O(N) 。

    1 寻址和 hash 函数

    理想状态下 hash 足够大,每一数据保存在一个 hash 存储单元内,这样对于插入删除和查找某一个数据就可以直接得到。但是现实情况下 hash 表不可能无限大,而且理论上保存的数据的个数是没有限制的,这样保存的数据的数量就远远大于 hash 表的存储单元的数量。

    为了实现在 O(1) 内对数据进行插入删除和查找,就必须将一个数据映射到 hash 表中的固定位置,这个映射函数就是 hash 函数。 Hash 函数通过对数据进行计算得到一个在 hash 表中的位置地址。

    要选择较好的 hash 函数,以及 hash 表存储单元的数量,这样才能使保存在 hash 表中的数据均匀分布。

    理想状态不太可能实现,由于存储的数据数量远远大于 hash 表存储单元的数量,所以再好的 hash 函数也可能使不同的数据得到相同的映射位置,这就造成了冲突。但是好的 hash 函数可以将这种冲突降到最低。

    2 分离链接

    解决这种冲突的第一种方法是借助链表来实现,就是将数据实际存放在与 hash 表存储单元相链接的链表中,而不是 hash 的存储单元中。

    当产生冲突的时候,将两个数据都链接在同一 hash 存储单元保存的链表中。当一个存储单元保存的链表中有多个数据的时候,对于链表后面的数据的查找添加和删除就是不是严格意义上的 O(1) 了。一个好的 hash 函数可以使得这个链表很短。最坏情况下,当所有的数据都保存在一个 hash 单元指定的链表中的时候,那么这个 hash 就和链表一样了。

    3 开放地址

    使用开放地址方法解决冲突的时候,数据仍然保存在 hash 表的存储单元中,但是当冲突发生的时候,要再次计算新的地址。

    常用的开放地址法是线性探查,就是当对一个数据进行插入删除或者查找的时候,通过 hash 函数计算,发现这个位置不是要找的数据,这时候就检查下一个存储单元,一直找到要操作的数据为止。

    除了线性探查外还有二次探查,再 hash 等等方法,都是当一次计算得到的位置不是要找到的数据的时候,怎样再次确定新的位置。

    4 完全hash表

    采用分离链表的方式解决冲突的时候,当多个数据被映射到一个地址的时候,它们就形成了一个链表,要操作这其中的一个数据,那么就必须在这个链表中进行操作。如果 hash 函数选择的好的话,链表会很短,这样的操作近似 O(1) ,但并不是精确的等于 O(1) ,它与链表的长度有关。对于数据的访问的最坏情况的访问也是 O(1) 的 hash 叫做完全 hash 表。

    这样的 hash 表是一个两级的 hash 表,第一级的 hash 与使用分离链接方法的 hash 一样,但是 hash 存储单元中指向的不是一个链表,而是另一个 hash 表。

    要小心的选择一级以及二级的 hash 函数可以完全保证在二级 hash 表中不会出现冲突。

    5 常用实现算法

    1. 直接定址法 :地址集合 和 关键字集合大小相同
    2. 数字分析法 :根据需要hash的 关键字的特点选择合适hash算法,尽量寻找每个关键字的 不同点
    3. 平方取中法:取关键字平方之后的中间极为作为哈希地址,一个数平方之后中间几位数字与数的每一位都相关,取得位数由表长决定。比如:表长为512,=2^9,可以取平方之后中间9位二进制数作为哈希地址。
    4. 折叠法:关键字位数很多,而且关键字中每一位上的数字分布大致均匀的时候,可以采用折叠法得到哈希地址,
    5. 除留取余法除P取余,可以选P为质数,或者不含有小于20的质因子的合数
    6. 随机数法:通常关键字不等的时候采用此法构造哈希函数较恰当。 

     实际工作中需要视不同的情况采用不同的hash函数

    1. 考虑因素:计算哈希函数所需要的时间,硬件指令等因素。
    2. 关键字长度
    3. 哈希表大小
    4. 关键字分布情况
    5. 记录查找的频率。(huffeman树)

    (未完待续)

  • 相关阅读:
    sql 查询当前数据库所有表格以及所有表格数据条数
    MVC AjaxOptions 中的OnSuccess方法执行多次的问题
    已知当前地理位置经纬度查询几个点中最近的一个地点demo
    微信分享ios设备没有分享图标安卓有分享图标 (分享功能没有问题)
    摇一摇js 实现
    linq 的switch实现
    启动服务器脚本
    关于网站的优化
    Ubuntu纯命令行安装并配置Teamviewer
    在Jupyter中使用自定义conda环境
  • 原文地址:https://www.cnblogs.com/alwayswangzi/p/6494545.html
Copyright © 2020-2023  润新知