python 哈希表_数据检索之哈希算法

一、哈希算法基本原理

(一)哈希算法的相关概念

哈希(Hash),也称为散列,是一种重要的存储方式,也是一种常见的检索方法。它是把任意长度的输入通过哈希算法变换成固定长度的输出。其中该输出就是哈希值。哈希值的空间通常远小于输入的空间,是一种压缩映射。由于不同的输入可能会散列成相同的输出,因此无法从哈希值来确定唯一的输入值。

哈希方法的主要思想是根据结点的关键码值来确定其存储地址,即以关键码值自变量,通过一定的函数关系,计算出对应的函数值,并将该值解释为结点的存储地址。在进行数据检索时,用同样的方法计算地址,然后在哈希表相应单元中找到需要的结点,即可完成数据的快速检索。

总的来说,哈希算法虽然被称为算法,但实际上它更像是一种思想。它没有一个固定的公式,因此只要符合哈希思想的算法都可以被称为是哈希算法。

(二)哈希函数的构建

首先,需要假设处理值为整型关键码,保证可以建立一种关键码与正整数之间一一对应的关系,从而把该关键码的检索转化为对应正整数的检索。然后,需要假定哈希函数的值落在0到M-1之间。另外,在选取哈希函数的过程中需要满足一定的原则:(1)运算尽可能简单(2)函数的值域必须在哈希表的范围内(3)尽可能使得结点均匀分布,让不同的关键码具有不同的哈希值(4)需要考虑各种因素,如关键码长度、哈希表大小、关键码分布情况、记录的检索频率等。

常用的哈希函数构建方法包括除留余数法、乘余取整法、平方取中法、数字分析法、基数转换法等。

1 除留余数法

除留余数法是将关键码除以M并取余数作为存储地址。通常选择哈希表长度作为M值。该方法几乎是最简单的哈希方法。

2 乘余取整法

乘余取整法是先将关键码乘以常数A(0),提取乘积小数部分,然后乘以整数n并对结果向下取整作为存储地址。

3 平方取中法

平方取中法是先求关键码的平方值,从而扩大相近数的差别,然后根据哈希表长度取中间几位数作为哈希值。由于一个乘积的中间几位数与乘数的每一数位都相关,因此由此产生的存储地址较为均匀。

4 数字分析法

数字分析法是取数据元素关键字中某些取值较均匀的数字位作为存储地址的方法。该方法分析关键字集中的全体,并从中提取分布均匀的若干位或它们的组合,当关键字的位数很多时,可以通过对关键字的各位进行分析,丢掉分布不均匀的位,作为哈希值。需要注意的是,该方法只适用于所有关键字已知的情况。

5 基数转换法

基数转换法是将关键码值看成另一种进制的数再转换成原来进制的数,然后选其中几位作为存储地址。

除此之外还有很多方法,如直接定址法、折叠法、随机数法、旋转法等。单一的构建方法往往具有一定的局限性,因此为了获得良好的哈希函数,可以将几种方法联合起来使用,比如先进行基数转换,再进行平方或者乘余取整等。理论上来说,只要哈希均匀就可以随意拼凑。

(三)哈希算法处理冲突的方法

通过构建性能良好的哈希函数可以一定程度上减少冲突,但是无法完全避免冲突,因此解决冲突是哈希算法的另一个关键问题。解决冲突常用的方法有四种,分别为开放定址法、再哈希法、链地址法和建立公共溢出区。

1 开放定址法

开放定址法是当关键字的存储地址出现冲突时,以现有地址为地址,产生另一个哈希地址,如果还有冲突就继续生成,知道找到一个不冲突的哈希地址,将相应元素存入其中。

2 再哈希法

再哈希法是同时构建多个不同的哈希函数,当地址发生冲突时,再按照下一种哈希函数计算存储地址,知道冲突不再产生。这种方法不易产生聚集,但是增加了计算时间。

3 链地址法

链地址法是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,使得查找、插入和删除主要在同义词链中进行。该方法主要适用于经常进行插入和删除的情况。

4 建立公共溢出区

建立公共溢出区是将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素一律填入溢出表。

二、哈希算法在Python中的实现 (一)hash()函数

在Python中有内置的哈希函数hash(),可以返回一个对象的哈希值。需要注意的是,这里的对象指的是数字、字符串,而不能直接用于list、set、dictionary等。示例代码及结果如下:

773bfc20aac33f94b068e6a17f4626fe.png

运行代码发现,相同字符串在同一次运行时的哈希值是相同的,但是不同次运行的哈希值不同。这是由于Python的字符串哈希算法有一个启动时随机生成的机制,因此存在随机化现象,即对同一个字符串输入,不同解释器进程得到的哈希结果可能不同。因此当需要做可重现可跨进程保持一致性的哈希时,需要用到hashlib模块。

(2)hashlib模块

hashlib提供了常见的摘要算法,如MD5,SHA1等等。MD5算法示例代码如下:

import hashlib

md5 = hashlib.md5()

data = "明天你好"

md5.update(data.encode('utf-8'))

print(md5.hexdigest())

输出结果:

57acf16ede2a016646f0a74461602969.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值