python数据结构与算法--什么是Hash|哈希函数?

目录

一,什么是哈希函数?

二,哈希表(hash table)原理

三,为什么不是所有的 hash 函数都可以被用来加密?

四,哈希碰撞(hash collision)的解决方式

五,什么是好的哈希函数?

六,哈希函数的构造方法

七,为什么不能对可变的对象进行 hash 处理?

八,大型网站如何利用 hash 函数保护用户密码?

九,Python3.x 增加的随机性

十,其他 hash 算法

   

背景

哈希(hash)算法,原先是一种被用在资料编码中的技术,可以被用来加密要隐藏的资料,还可以被用来,比较不同文本的相似度。哈希算法属于信息摘要(Message Digest)算法。

区块链技术背后的底层原理之一,即为哈希算法。理解了哈希函数,自然就会理解区块链的挖矿模式。

全面的 hash 算法列表网址: ( http://burtleburtle.net/bob/hash/ )


一,什么是哈希函数?

哈希函数(hash function): 也称为「散列函数」或「杂凑函数」。

h = H(M)

哈希函数将任意长度的消息 M,映射成为一个长度较短且长度固定的值 H(M)。H(M)即为散列值或哈希值(hash value)。

哈希算法是一种信息摘要(Message Digest)算法。对象的 hash 值比原对象拥有更低的内存复杂度。是一种压缩映射。

根据哈希函数所建立的表为哈希表。


2

二,哈希表(hash table)原理

哈希表(hash table)|散列表,是根据关键码值进行访问的数据结构。属于键和值之间的一 一对应关系。

通常提供查找(search),插入(insert),删除(delete)等操作。跟数组一样都是一种数据结构。与字典类似,通过键值对(key-indexed)来保存数据。

目前大部分动态语言的实现中都使用了哈希表。有些语音将哈希表乘坐字典,但是哈希表跟字典并不完全相同。哈希表是弱类型的,而字典是强类型的。

哈希表查找一个元素的时间复杂度为0(1),效率极高,这也是它的一个重要优点。

键(key):操作数据的标识。

槽(bucket):用于存放数据的单元。

创建自己的哈希表


python数据结构与算法--什么是Hash|哈希函数?_第1张图片
python数据结构与算法--什么是Hash|哈希函数?_第2张图片

三,大型网站如何利用 hash 函数保护用户密码?

即使大型网站的数据库被攻破,也不会造成太大损失。为什么呢?这涉及到了哈希函数的两个主要特性:不可逆性与抗碰撞性。

利用哈希函数对用户密码进行加密:用户设置完密码后,会被转换成 hash 值,并保存到数据库中。如下图。

pip3 installsimhash

​被保存的只是转换后的哈希值,而不是原密码。

由于哈希(hash)函数是不可逆的,只能由输入产生输出,不能由输出产生输入。系统服务器无法根据每个 hash 值逆过来推算出原密码。因此即使是后台工作人员,也无法得知用户的原密码。

用户登录的时候,输入密码,经过 hash 操作后转换成 hash 值,再与数据库中被保存的 hash 值进行对比。hash 值完全一样,则密码正确。

   


四,为什么不是所有的 hash 函数都可以被用来加密?

不是所有的 hash 函数都可以被用来加密,这就涉及到了哈希碰撞(hash collision)。

对于 hash 算法,一般情况下,不同的数据会生成不同的哈希值。但是如果两个不同的数据,经过 Hash 函数计算后,得到的 Hash 值一样,则为哈希碰撞(collision)。

即 f (key1) = f(key2)

哈希碰撞无法被完全避免。只能降低其发生概率。

碰撞攻击则是找到另一个跟原密码具有相同 hash 值的字符串。

为了提高安全性,只有加密哈希函数(cryptgraphic hash functions)可以被用来加密。如 SHA256, SHA512, Ripemd, WHIRLPOOL 等 。这类函数的 hash 破解异常困难,几乎不太可能出现 hash 碰撞。

   


五,哈希碰撞(hash collision)的解决方式

一,开放寻址法(open addressing)

二,拉链法

开放寻址法的总体设计原理为:出现哈希碰撞时,重新检测一个空闲位置,并插入。

但是这样会产生一个问题,即占用其他槽位的空间,以致于后续的插入操作更容易出现冲突。因此在利用开放寻址法的时候,装载因子最好保持在0.5以下。

装载因子 = 保存的元素数量/容量

[1]开放寻址法有:

线性探测器(Linear Probing)

二次探测法(Quadratic Probing)

随机探测法

双散列(Double hashing)

再哈希法

建立一个公共溢出区

线性探测法介绍:

线性探测法为开放寻址法最简单的一种实现。

线性探测法用来解决哈希碰撞的原理是:当某个被给定键在散列表中的对应单元已被占用时(即我们向当前哈希表写入数据时发生了冲突),会检测散列表中离冲突单元最近的空闲单元。并把该键值对写入到下一个不为空的位置。

只要哈希表未被填满,总能找到一个不发生冲突的单元。

再哈希法:

再哈希法用来解决哈希碰撞的原理是:两个值产生冲突时,通过下面算式,计算另一地址,直到不再冲突。

Hi = R * Hi(key) [i = 1,2,...k]

同样的关键字,同样的哈希函数,用不同的处理哈希碰撞的方法,得到的哈希函数值也不同。



   

六,什么是好的哈希函数?

哈希表的关键点就在于哈希函数的选择。

若对于关键字集合中的,任意一个关键字,经过哈希函数,映像到地址集合中,任何一个地址的概率是相等的,则为均匀散列函数(uniform hash function)。也即好的哈希函数。

这种方法通过将关键字映射到“均匀分布的随机地址”来减少冲突。

目前的哈希算法都能良好的将key进行比较均匀的分布。



   

七,哈希函数的构造方法:

直接定址法

除留余数法

数字分析法

折叠法

平方取中法

直接定址法:取关键字,或关键字的某个线性函数值,为哈希地址。

即:H(key) = key 或 H (key) = a * key + b

链地址法:将所有相似关键词的记录存储在同一线性链表中。



   

八,为什么不能对可变的对象进行 hash 处理?

首先要了解两个概念,可哈希性(hashable)与不可哈希性(unhashable)。

可哈希性(hashable):可哈希的数据类型为不可变的数据结构(如字符串 srt,元组 tuple,对象集 objects 等)。这种数据被称为可哈希性。

不可哈希性:不可哈希的数据类型,为可变的数据结构(如字典 dict,列表 list 和集合 set 等)。

如果对可变的对象进行哈希处理,则每次对象更新时,都需要更新哈希表。这样我们则需要将对象移至不同的数据集,这种操作会使花费过大。

因此设定不能对可变的对象进行 hash 处理。

   


九,Python3.x 增加的随机性

Python3.x添加了 hash 算法的随机性,以提高安全性,因此对于每个新的 python 调用,同样的数据源生成的结果都将不同。 下面为算法实例。

python数据结构与算法--什么是Hash|哈希函数?_第3张图片

哈希方法有(MD5, SHA1, SHA256 与 SHA512 等)。常用的有 SH256 与 SHA512,即上文提到的加密哈希函数(cryptgraphic hash functions)。MD5 与 SHA1 不再常用。

MDH5 (不常用)

SHA1 (不常用)

SHA256 (常用)

SHA512 (常用)


   


十,其他 hash 算法**

1. simhash 算法:

这是一种局部敏感的 hash 算法,它产生的签名在一定程度上可以表征原内容的相似度。

可以被用来比较文本的相似度。

如下代码安装 simhash 模块。

pip3 installsimhash

2. Imagehash 算法:

Imagehash 算法为感知哈希算法(perceptual Hash Algorithm)。

常被用来检测图像和视频的差异。

如下代码安装 Imagehash 模块。

pip3 install simhash

例如:可以通过比较两张图片的 hash 值来判断相似度。下面为比较两张相似图片的代码示例。

python数据结构与算法--什么是Hash|哈希函数?_第4张图片

​​

python数据结构与算法--什么是Hash|哈希函数?_第5张图片

输出为:

hash(image1) =00fd43c3**f**fffffff

hash(image2) =00fd43c3f**e**ffffff

从输出结果可以看到两张图片的 hash 值非常相似。相似的图片可以生成相似的哈希值是 Imagehash 的特点。

后续再详细更新哈希碰撞的解决方式

python数据结构与算法--什么是Hash|哈希函数?_第6张图片

你可能感兴趣的:(python数据结构与算法--什么是Hash|哈希函数?)