概述

  • 哈希表是一种可以满足快速查找数据结构,时间复杂度接近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. python学习-Day8

    目录 作业讲解 数据类型内置方法3 字典 ( dict ,可变类型) 类型转换 -- dict() 需要掌握的方法 按key取值(可存可取) 统计字典中键值对的个数(len) 成员运算 删除键值对 获 ...

  2. xpath & csv文件读写

    原理:拿到网页源代码并且进行分析 关键词:etree     .xpath      a[@href="dapao"]      a/@href       text() impo ...

  3. 如何改变函数内部 this 的指向

    一.函数内 this 的指向 1. this 的指向是当调用函数时确定的,调用的方式不同,this 的指向也就不同. 1.1 this 一般是指向调用者. 函数类型 this 的指向 普通函数 Win ...

  4. python3 Softmax函数

    Softmax函数公式 Softmax的作用简单的说就计算一组数值中每个值的占比 import torch import torch.nn.functional as F # 原始数据tensor y ...

  5. 使用本地自签名证书为 React 项目启用 https 支持

    简介 现在是大前端的时代,我们在本地开发 React 项目非常方便.这不是本文的重点,今天要分享一个话题是,如何为这些本地的项目,添加 https 的支持.为什么要考虑这个问题呢?主要有几个原因 如果 ...

  6. 沁恒CH32V103C8T6开发环境笔记

    CH32V103C8T6 CH32V103C8T6是沁恒的RISC-V内核MCU, 基于RISC-V3A处理器, 内核采用2级流水线处理,设置了静态分支预测.指令预取机制,支持DMA. 主要参数如下 ...

  7. PHP反序列化链分析

    前言 基本的魔术方法和反序列化漏洞原理这里就不展开了. 给出一些魔术方法的触发条件: __construct()当一个对象创建(new)时被调用,但在unserialize()时是不会自动调用的 __ ...

  8. final变量、方法与类

    学习内容: 一.final变量 1.设定为final的变量,其值不可被改变. 2.final定义的变量必须在声明时对其进行赋值操作. 3.final可以修饰对象.被修饰为final的对象,只能恒定指向 ...

  9. CF1601F Two Sorts

    CF1601F Two Sorts 给定 \(n\),将 \(1\sim n\) 按照字典序排序,\(a_i\) 表示第 \(i\) 小的数,求: \[\left(\sum_{i=1}^{n} ((i ...

  10. AtCoder ABC 250 总结

    AtCoder ABC 250 总结 总体 连续若干次一样的结果:30min 切前 4 题,剩下卡在 T5 这几次卡在 T5 都是一次比一次接近, 什么 dp 前缀和打挂,精度被卡,能水过的题连水法都 ...