文章目录

  • 一、散列(Hashing)的概念
    • 举例说明
  • 二、完美散列函数
    • 1. 数据的一致性校验
    • 2. 完美散列函数用于数据的一致性校验

一、散列(Hashing)的概念

在查找算法中,如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度。现在我们沿着这个思路,在存放数据时花点心思:构造一个新的数据结构,能使得查找算法的复杂度降到 O ( 1 ) O(1) O(1)。

如果我们事先能知道要找的数据项应该出现在数据集中的什么位置,就可以直接到那个位置看看数据项是否存在即可。于是,现在的问题就成了:如何由数据项的值来确定其存放位置

  • 散列表(hash table,又称哈希表)是一种数据集,其存储数据项的方式,有利于将来快速的查找定位

  • 散列表中的每一个存储位置,称为槽(slot),可以用来保存数据项,每个槽有一个唯一的名称

  • 实现从数据项到存储槽名称的转换的,称为散列函数(hash function)。

  • 而散列就是指散列函数所进行的那一过程,即将任意数据项转换为固定长度输出的过程。

举例说明

例如:一个包含11个槽的散列表,槽的名称分别为0~10。在插入数据项之前, 每个槽的值都是None,表示空槽。

散列函数接受数据项作为参数,返回整数值0~10,表示数据项存储的槽号(名称)。

“求余数”是一种常用的散列方法,将数据项除以散列表的大小,得到的余数作
为槽号。因为散列函数返回的槽号必须在散列表大小范围之内,所以一般会对散列表大小求余。(实际上“求余数”方法会以不同形式出现在所有散列函数里)

我们这里也使用求余运算作为散列函数: h ( i t e m ) = i t e m % 11 h(item) = item\% 11 h(item)=item%11

数据项(item) 散列值(hash value)
54 10
26 4
93 5
17 6
77 0
31 9

按照散列函数 h ( i t e m ) h(item) h(item),为每个数据项计算出存放的位置之后,就可以将数据项存入相应的槽中。槽被数据项占据的比例称为散列表的“负载因子”,这里负载因子为6/11。

数据项都保存到散列表后,查找就无比简单:我们只需要使用同一个散列函数,对查找项进行计算,测试下返回的槽号所对应的槽中是否有数据项即可。实现了 O ( 1 ) O(1) O(1)时间复杂度的查找算法。

此时,我们发现了一个问题:上面的数据相当凑巧,各自占据了不同槽,假如还要保存44, h ( 44 ) = 0 h(44)=0 h(44)=0,它跟77被分配到同一个0号槽中,这种情况称为“冲突collision”,我们后面会讨论到这个问题的解决方案。

二、完美散列函数

给定一组数据项,如果一个散列函数能把每个数据项映射到不同的槽中,那么这个散列函数就可以称为“完美散列函数”。

对于固定的一组数据,总是能想办法设计出完美散列函数。但如果数据项经常性的变动,就很难有一个系统性的方法来设计对应的完美散列函数。当然,冲突也不是致命性的错误,我们会有办法处理的。

获得完美散列函数的一种方法是扩大散列表的容量,大到所有可能出现的数据项都能够占据不同的槽。但这种方法对于可能数据项范围过大的情况并不实用,假如我们要保存手机号(11位数字),完美散列函数得要求散列表具有百亿个槽!会浪费太多存储空间。

综上,好的散列函数需要具备特性:

  • 冲突最少(近似完美);
  • 计算难度低(额外开销小);
  • 充分分散数据项(尽量均匀分布在各个槽中,以节约空间)。

1. 数据的一致性校验

由于完美散列函数能够对任何不同的数据生成不同的散列值,如果把散列值当作数据的“指纹”或者“摘要”,这种特性被广泛应用在数据的一致性校验上。

作为一致性校验的数据“指纹”函数需要具备如下的特性:

  • 压缩性:任意长度的数据,得到的“指纹”长度是固定的;
  • 易计算性:从原数据计算“指纹”很容易;(从指纹计算原数据是不可能的);
  • 抗修改性:对原数据的微小变动,都会引起“指纹”的大改变;
  • 抗冲突性:已知原数据和“指纹”,要找到相同指纹的数据(伪造)是非常困难的。

最著名的近似完美散列函数是MD5和SHA系列函数:

  • MD5(Message Digest)将任何长度的数据变换为固定长为128位(16字节)的“摘要”。128位二进制已经是一个极为巨大的数字空间:据说是地球沙粒的数量。
  • SHA(Secure Hash Algorithm)是另一组散列函数:
    • SHA-0/SHA-1输出散列值160位(20字节),160位二进制相当于10的48次方,地球上水分子数量估计是47次方。
    • SHA-256/SHA-224分别输出256位、224位,256位二进制相当于10的77方,已知宇宙所有基本粒子大约是72~87次方。
    • SHA-512/SHA-384分别输出512位和384位。

虽然近年发现MD5/SHA-0/SHA-1三种散列函数,能够以极特殊的情况来构造个别碰撞(散列冲突),但在实用中从未有实际的威胁。

Python自带MD5和SHA系列的散列函数库:hashlib,包括了md5 / sha1 / sha224 / sha256 / sha384 / sha512等6种散列函数。简单用法可以参考我的文章:传送门。

2. 完美散列函数用于数据的一致性校验

为每个文件计算其散列值,仅对比其散列值即可得知是否文件内容相同。用于网络文件下载完整性校验:

  • 文件下载:文件提供网站通常会提供散列值,可以帮助用户校验下载的文件是否有损坏,或者被篡改过。
  • 网盘秒传:我们在向网盘上传文件时(尤其是电影),由网盘客户端在本地计算好散列值,上传给网盘服务器,网盘服务器就会寻找是否已有与该散列值相同散列值的文件。如果有,就说明该文件已经被人上传到了,无需重复上传,只需将已有文件链接到我们的账户下,以此实现秒传。
  • 密码保存:加密形式保存密码,仅保存密码的散列值,用户输入密码后,计算散列值并比对;无需保存密码的明文即可判断用户是否输入了正确的密码。
  • ……

数据结构与算法——17. 散列(哈希)与完美散列函数相关推荐

  1. 数据结构与算法 ~ 查找 ~ 散列查找(哈希~线性探查法和二次探查法)

    数据结构与算法 ~ 查找 ~ 散列查找(哈希~线性探查法和二次探查法) /*search-hash*/ #include<math.h> #include<stdio.h> # ...

  2. Java 国密算法 SM3 散列哈希使用

    Java 国密算法 SM3 散列哈希使用 文章目录 Java 国密算法 SM3 散列哈希使用 引入依赖 计算散列哈希 引入依赖 <dependency><groupId>org ...

  3. 数据结构之查找算法:散列查找

    查找算法:散列查找 思维导图: 散列函数和散列表: 构造散列函数的要求: 构造散列函数的方法: 直接定址法: 除留取余法: 数字分析法: 平方取中法: 折叠法: 解决冲突的方法: 开放定址法: 线性探 ...

  4. 10_JavaScript数据结构与算法(十)哈希表

    JavaScript 数据结构与算法(十)哈希表 认识哈希表 哈希表是一种非常重要的数据结构,几乎所有的编程语言都直接或者间接应用这种数据结构. 哈希表通常是基于数组实现的,但是相对于数组,它存在更多 ...

  5. 数据结构与算法笔记(十五)—— 散列(哈希表)

    一.前沿 1.1.直接寻址表 当关键字的全域U比较小时,直接寻址是一种简单而有效的技术.假设某应用要用到一个动态集合,其中每个元素都有一个取自全域U={0,1,-,m-1)的关键字,此处m是一个不很大 ...

  6. 聊聊传说中的散列哈希Hash算法,以及Java中的HashTable,HashMap,HashSet,ConcurrentHashMap......

    建议本文结合java源码来阅读,看了之后就什么都懂了,还有参考文献. 散列(Hash) 是一种按关键字编址的存储和检索方法 散列表(HashTable)根据元素的关键字确定元素的位置 散列函数(Has ...

  7. Java数据结构和算法:HashMap,哈希表,哈希函数

    1. HashMap概述 HashMap是基于哈希表的Map接口的非同步实现(Hashtable跟HashMap很像,唯一的区别是Hashtalbe中的方法是线程安全的,也就是同步的).此实现提供所有 ...

  8. 【数据结构与算法】散列表

    一.散列表的由来? 1.散列表来源于数组,它借助散列函数对数组这种数据结构进行扩展,利用的是数组支持按照下标随机访问元素的特性. 2.需要存储在散列表中的数据我们称为键,将键转化为数组下标的方法称为散 ...

  9. 【Java数据结构与算法】第十章 哈希表和二叉树

    第十章 哈希表和二叉树 文章目录 第十章 哈希表和二叉树 一.哈希表 1.介绍 2.代码实现 二.二叉树 1.介绍 2.遍历二叉树 3.查找二叉树 4.二叉树删除节点 5.二叉树综合实例 一.哈希表 ...

最新文章

  1. 《HTML5与CSS3实战指南》——2.5 构建The HTML5 Herald
  2. SAP QM 事务代码QAC2的BUG?
  3. mysql进阶(十五) mysql批量删除大量数据
  4. 音视频技术开发周刊 84期
  5. 利用微信登录掘金网站的HTTP请求分析
  6. Express 极速掌握
  7. python就业方向-看完Python这五大就业方向的薪资待遇,你选择哪个?
  8. Opencv单目标定flag的设定
  9. android alertdialog 自定义时间,Android自定义dialog可选择展示年月日时间选择栏
  10. VC动态库可以嵌套调用
  11. 微信/qq/防撤回插件
  12. 在 Java 应用程序中访问 USB 设备
  13. 百度url提交入口 百度网站收录提交入口网址
  14. 【动态规划】数字三角形c语言
  15. vue实现导出表格数据
  16. 活动并发测试-1000个不同用户同时并发请求报名笔记
  17. 计算机控制运行内存,运行内存
  18. 计算机专业高级工程师考哪些专业,高级工程师职称考试项目有哪些
  19. CSDN是怎么样的一个网站
  20. 解读新零售:什么叫做人货场的重构

热门文章

  1. 【微信小程序】小程序实现文件的上传及预览,以PDF文件为例。
  2. 什么是闭包?闭包的优缺点? 1
  3. 使用Nightwatch进行端到端测试
  4. Windows上安装Linux
  5. Pytorch-模型参数:named_parameters()、parameters()、state_dict()区别
  6. Fiddler4 手机抓包
  7. 【观察】揭秘:中信银行信用卡新核心系统自研之路
  8. 在CMD上运行javac前应该这样做
  9. Timer延时任务和ScheduledThreadPool执行延时任务
  10. scanf()函数的用法