概述

  • 哈希表是一种可以满足快速查找数据结构,时间复杂度接近O(1)。
  • 哈希函数是无限集到有限集的映射。
  • 处理数据量大,查找效率要求高时推荐使用hash容器。
  • 问题:
    • 什么情况下考虑使用哈希容器?
    • 常用的哈希思路有哪些?
    • 评判哈希算法标准有哪些?
    • 哈希冲突是如何产生的?如何解决?
    • 如何构造一个hash算法?应注意哪些问题?

评判哈希算法标准

  • 效率高。
  • 映射分布均匀。

基础hash思路

直接寻址法:

取关键字key,使用线性函数 Hash(key) = a * key + b。

数字分析法:

在一个班级里,同龄学生很多。在取学生年龄作为key时,应避免以年份作为key组成部分。

平方取中法:

key取平方,截取中间的几位作为新的key。数学计算的性质乘积中间几位和乘数每一位都有关,充分混合key每一位对生成的哈希值的影响,使映射分布更均匀。

取余法:

Hash(key) = key % m

相乘取整法:

Hash(key) = floor(frac(key * A), m), 0<A<1

  • floor 取整,frac 取小数
  • 此法避免像除余法中结果对m过于依赖。

随机数法

Hash(key) = rand(key)

  • 据我所知C#的object采用此方法,使用元数据中的几位存hash值。

折叠法:

将关键字按固定长度分成几段然后相加。

  • 如:Hash(1234,m = 2) = 46。
  • 关键字较长时可以考虑使用此方法。

哈希冲突

产生原因

由于哈希函数是无限集到有限集的映射,换而言之,有限集的元素对应n个无限集的元素,哈希碰撞是不可避免的。

解决办法

开放地址法

当关键字key的哈希地址p=H(key)出现冲突时,递归调用p = Hi(p)直到没有冲突。

Hi=(H(key)+di)Hi=(H(key)+di) % m   i=1,2,,3....,ni=1,2,,3....,n

  • H(key) 为哈希函数
  • m 为表长
  • di 为增量序列

根据增量序列di的不同,又分为:

  • 线性探测:di = 1,2,3,......
  • 二次探测: di = ±1^2, ±2^2,.......
  • 随机探测: di = random(di,seed)
    • random 为 无状态的伪随机发生函数(所谓无状态,即无论多少次调用,random(a) = b不变)
    • seed 一个确定不变的随机数种子

链式地址法

结构示意

pos1

pos2 -> val -> val

pos3 -> val

pos4

...

无限集映射到有限集,有限集的每个元素对应一个链表,链表存储无限集映射到有限集的n个元素。

再哈希法

Hi=RHi(key)i=1,2,…,k

递归调用哈希函数序列中的函数,直到没有冲突。

建立公共溢出区法

建立溢出链表,如发生哈希碰撞,则使用溢出链表。

哈希冲突解决方法优缺点分析

开放散列:链式地址法(桶链法)

  • 优点:

    • 添加删除方便,避免动态调整开销
    • 桶链表内存动态分配,减少内存浪费
    • 当哈希表size很大时,指针的性能消耗可以忽略
  • 缺点:
    • 动态分配内存,内存不紧凑,随机访问性差,序列化性能差。
    • 对于预先知道所有元素,可以实现没有冲突的完美hash函数,此时效率会远低于封闭散列。

封闭散列:开放地址法,再哈希法 ...

  • 优点:

    • 内存紧凑,随机访问性能好,序列化性能好。
    • 预先知道所有元素e,可以实现完美hash函数,此时效率远高于开放散列。
  • 缺点:
    • 所有条目数量不能超过数组的长度,扩容/收紧频繁,性能消耗大。
    • 碰撞探测消耗性能。
    • 当数组长度很大时,有内存浪费。

哈希算法进阶实例分析

这是取自lua5.4的

-- lua 5.4

unsigned int luaS_hash (const char *str, size_t l, unsigned int seed,
size_t step) {
unsigned int h = seed ^ cast_uint(l);
for (; l >= step; l -= step)
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h;
} #define lmod(s,size) \
(check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1)))))

(h << 5) + (h >> 2)

= (((h << 5) << 2) + ((h >> 2) << 2) >> 2)

= ((h << 7) + h) >> 2

= (129 * h) >> 2

  • 和伪随机数生成算法一样,要让生成的数尽量随机--二进制数的每一个位取0或1的概率都是50%。

  • 移位,异或运算充分混合每一位的影响,而加法运算引起多个位的反转,使hash值的每一个位更加不可预测,以接近不可逆的单向函数。

  • (h << 5) + (h >> 2) = (129 * h) >> 2。 乘法可以被拆分为加法和移位的组合(即(h << 7)+h ),以混合哈希值。不过(h << 7 - h) = 127h 会更好些,127是梅森素数(2^n -1)。与线性同余算法(LCG)生成伪随机数一样,梅森素数127,只需一次移位运算和一次加法运算,且不会被分解,随机数分布更加均匀。

    • 非素数会被分解成更小的素数的乘积,参与运算时容易被分解,上例中a和c可以提取公因数d,周期 = n = c/d。
  • a%b = a&(b-1) 当 b = 2^n 时等式成立,lua哈希表的长度保证符合等式成立的条件,lmod使用位运算代替取余运算,效率更高。

  • 算法实际应用详情请参考我的文章

进阶哈希算法

下面是一些进阶哈希算法的思路,需要花费一些时间学习。

Hash 哈希表和算法思路详解的更多相关文章

  1. C#中哈希表(HashTable)的用法详解以及和Dictionary比较

    1.  哈希表(HashTable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对, ...

  2. C#中哈希表(HashTable)的用法详解

    描述: 哈希表存放 key.values ,key值可以用于快速调取用,values 对应object类型,也就是说所有类型. 实例: 1.HashTable存放学生的成绩 Hashtable ht1 ...

  3. 转 C#中哈希表(HashTable)的用法详解

    看了一遍有关哈希表的文字,作者总结的真是不错 .收藏起来 1.  哈希表(HashTable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提 ...

  4. javascript常用经典算法实例详解

    javascript常用经典算法实例详解 这篇文章主要介绍了javascript常用算法,结合实例形式较为详细的分析总结了JavaScript中常见的各种排序算法以及堆.栈.链表等数据结构的相关实现与 ...

  5. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  6. 各大公司广泛使用的在线学习算法FTRL详解

    各大公司广泛使用的在线学习算法FTRL详解 现在做在线学习和CTR常常会用到逻辑回归( Logistic Regression),而传统的批量(batch)算法无法有效地处理超大规模的数据集和在线数据 ...

  7. MD5算法步骤详解

    转自MD5算法步骤详解 之前要写一个MD5程序,但是从网络上看到的资料基本上一样,只是讲了一个大概.经过我自己的实践,我决定写一个心得,给需要实现MD5,但又不要求很高深的编程知识的童鞋参考.不多说了 ...

  8. 2. EM算法-原理详解

    1. EM算法-数学基础 2. EM算法-原理详解 3. EM算法-高斯混合模型GMM 4. EM算法-高斯混合模型GMM详细代码实现 5. EM算法-高斯混合模型GMM+Lasso 1. 前言 概率 ...

  9. 一致性算法RAFT详解

    原帖地址:http://www.solinx.co/archives/415?utm_source=tuicool&utm_medium=referral一致性算法Raft详解背景 熟悉或了解 ...

随机推荐

  1. Spring 源码(6)BeanFactoryPostProcessor怎么执行的?

    上一篇文章 https://www.cnblogs.com/redwinter/p/16167214.html 解读了如何进行自定义属性值的编辑器的解析器,并且还介绍了BeanFactory的准备过程 ...

  2. 阿里新零售中的智能补货(I)— 库存模型

    文章作者:阿里零售通算法团队 出品社区:DataFun 导读: 零售通作为阿里巴巴新零售的八路大军之一,肩负着"共建智能分销平台"和"让百万小店拥抱DT时代"的 ...

  3. Linux磁盘和文件系统知识总结

    硬盘操作 为什么要给硬盘分区? 如果你需要在一块硬盘上用到多个文件系统,那么你就需要对硬盘进行分区,以便用不同的分区支持不同的文件系统.(但一个硬盘只能有一个分区表!)反过来说,如果你整块硬盘都用同样 ...

  4. 905. Sort Array By Parity - LeetCode

    Question 905. Sort Array By Parity Solution 题目大意:数组排序,偶数放前,奇数在后,偶数的数之间不用管顺序,奇数的数之间也不用管顺序 思路:建两个list, ...

  5. 好客租房27-state的基本使用

    5.1state的基本使用 状态:数据 是组件内部的私有数据 只能再组件内部使用 state的值是对象 表示一个组件中可以有多个数据 获取数据 this.state //导入react     imp ...

  6. 什么是请求参数、表单参数、url参数、header参数、Cookie参数?一文讲懂

    最近在工作中对 http 的请求参数解析有了进一步的认识,写个小短文记录一下. 回顾下自己的情况,大概就是:有点点网络及编程基础,只需要加深一点点对 HTTP 协议的理解就能弄明白了. 先分享一个小故 ...

  7. Python趣味入门9:函数是你走过的套路,详解函数、调用、参数及返回值

    1.概念 琼恩·雪诺当上守夜人的司令后,为训练士兵对付僵尸兵团,把成功斩杀僵尸的一系列动作编排成了"葵花宝典剑法",这就是函数.相似,在计算机世界,一系列前后连续的计算机语句组合在 ...

  8. 人体调优不完全指南「GitHub 热点速览 v.22.22」

    本周特推又是一个人体调优项目,换而言之就是如何健康生活,同之前的 HowToLiveLonger研究全因死亡率不同,这个项目更容易在生活中实践,比如,早起晒太阳这么一件"小事"便有 ...

  9. ERP采购收货在标准成本和移动平均价下的差别

    欢迎关注微信公众号:iERPer (ERP咨询顾问之家) ERP系统在处理主要的采购流程有: 下采购合同->下采购订单->收货->发票校验->付款(财务) 其中 收货和发票校验 ...

  10. QT 基于QScrollArea的界面嵌套移动

    在实际的应用场景中,经常会出现软件界面战场图大于实际窗体大小,利用QScrollArea可以为widget窗体添加滚动条,可以实现小窗体利用滚动条显示大界面需求.实现如下: QT创建一个qWidget ...