数据结构-Hash总结(二)

转载:http://blog.csdn.net/liufei_learning/article/details/19220391


理解Hash

哈希表(hash table)是从一个集合A到另一个集合B的映射(mapping)

映射是一种对应关系,而且集合A的某个元素只能对应集合B中的一个元素。但反过来,集合B中的一个元素可能对应多个集合A中的元素。如果B中的元素只能对应A中的一个元素,这样的映射被称为一一映射。这样的对应关系在现实生活中很常见,比如:

          A  -> B

          人 -> 身份证号

          日期 -> 星座

上面两个映射中, -> 身份证号一一映射的关系。在哈希表中,上述对应过程称为hashing。A中元素a对应B中元素b,a被称为键值(key),b被称为a的hash值(hash value)


映射在数学上相当于一个函数f(x):A->B。比如 f(x) = 3x + 2。哈希表的核心是一个哈希函数(hash function),这个函数规定了集合A中的元素如何对应到集合B中的元素。比如:

          A: 三位整数    hash(x) = x % 10    B: 一位整数

          104                               4

          876                               6

          192                               2

上述对应中,哈希函数表示为hash(x) = x % 10。也就是说,给一个三位数,我们取它的最后一位作为该三位数的hash值。


哈希表在计算机科学中应用广泛。比如在Git中,文件内容为键值,并用SHA算法作为hash function,将文件内容对应为固定长度的字符串(hash值)。如果文件内容发生变化,那么所对应的字符串就会发生变化。git通过比较较短的hash值,就可以知道文件内容是否发生变动。

再比如计算机的登陆密码,一般是一串字符。然而,为了安全起见,计算机不会直接保存该字符串,而是保存该字符串的hash值(使用MD5、SHA或者其他算法作为hash函数)。当用户下次登陆的时候,输入密码字符串。如果该密码字符串的hash值与保存的hash值一致,那么就认为用户输入了正确的密码。这样,就算黑客闯入了数据库中的密码记录,他能看到的也只是密码的hash值。上面所使用的hash函数有很好的单向性:很难从hash值去推测键值。因此,黑客无法获知用户的密码。(之前有报道多家网站用户密码泄露的时间,就是因为这些网站存储明文密码,而不是hash值.)

注意,hash只要求从A到B的对应为一个映射,它并没有限定该对应关系为一一映射。因此会有这样的可能:两个不同的键值对应同一个hash值。这种情况叫做hash碰撞(hash collision)或者hash 冲突。比如网络协议中的checksum就可能出现这种状况,即所要校验的内容与原文并不同,但与原文生成的checksum(hash值)相同。再比如,MD5算法常用来计算密码的hash值。已经有实验表明,MD5算法有可能发生碰撞,也就是不同的明文密码生成相同的hash值,这将给系统带来很大的安全漏洞。(参考hash collision)

Hash函数

Hash函数设计的好坏直接影响到对Hash表的操作效率。下面举例说明:

假如对上述的联系人信息进行存储时,采用的Hash函数为:姓名的每个字的拼音开头大写字母的ASCII码之和。

          address(张三)=ASCII(Z)+ASCII(S)=90+83=173;

          address(李四)=ASCII(L)+ASCII(S)=76+83=159;

          address(王五)=ASCII(W)+ASCII(W)=87+87=174;

          address(张帅)=ASCII(Z)+ASCII(S)=90+83=173;

假如只有这4个联系人信息需要进行存储,这个Hash函数设计的很糟糕。首先,它浪费了大量的存储空间,假如采用char型数组存储联系人信息的话,则至少需要开辟174*12字节的空间,空间利用率只有4/174,不到5%;另外,根据Hash函数计算结果之后,address(张三)和address(李四)具有相同的地址,这种现象称作冲突,对于174个存储空间中只需要存储4条记录就发生了冲突,这样的Hash函数设计是很不合理的。所以在构造Hash函数时应尽量考虑关键字的分布特点来设计函数使得Hash地址随机均匀地分布在整个地址空间当中。通常有以下几种构造Hash函数的方法:

1.直接定址法

取关键字或者关键字的某个线性函数为Hash地址,即address(key)=a*key+b;如知道学生的学号从2000开始,最大为4000,则可以将address(key)=key-2000作为Hash地址。

2.平方取中法

对关键字进行平方运算,然后取结果的中间几位作为Hash地址。假如有以下关键字序列{421,423,436},平方之后的结果为{177241,178929,190096},那么可以取{72,89,00}作为Hash地址。

3.折叠法

将关键字拆分成几部分,然后将这几部分组合在一起,以特定的方式进行转化形成Hash地址。假如知道图书的ISBN号为8903-241-23,可以将address(key)=89+03+24+12+3作为Hash地址。

4.除留取余法

如果知道Hash表的最大长度为m,可以取不大于m的最大质数p,然后对关键字进行取余运算,address(key)=key%p。在这里p的选取非常关键,p选择的好的话,能够最大程度地减少冲突,p一般取不大于m的最大质数。

5.数字分析法

假设关键字是以r为基的数,并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。       

例如有某些人的生日数据如下:

          年. 月. 日

          75.10.03
          85.11.23
          86.03.02
          86.07.12
          85.04.21
          96.02.15

经分析,第一位,第二位,第三位重复的可能性大,取这三位造成冲突的机会增加,所以尽量不取前三位,取后三位比较好

6.随机数法

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即

H(key)=random(key) ,其中random为随机函数。通常用于关键字长度不等时采用此法。


Hash冲突

哈希表处理冲突主要有开放寻址法、再散列法、链地址法(拉链法)和建立一个公共溢出区四种方法

通过构造性能良好的哈希函数,可以减少冲突,但一般不可能完全避免冲突,因此解决冲突是哈希法的另一个关键问题。创建哈希表和查找哈希表都会遇到冲突,两种情况下解决冲突的方法应该一致。下面以创建哈希表为例,说明解决冲突的方法。常用的解决冲突方法有以下四种:

1.开放定址法

这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:Hi=(H(key)+di)%m   i=1,2,…,n,其中H(key)为哈希函数,m 为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种:

(1) 线性探测再散列

          di=1,2,3,…,m-1

这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

(2) 二次探测再散列

          di=12,-12,22,-22,…,k2,-k2    ( k<=m/2)

这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

(3) 伪随机探测再散列

          di=伪随机数序列。

具体实现时,应建立一个伪随机数发生器,(如i=(i+p) % m),并给定一个随机数做起点。


例如,已知哈希表长度m=11,哈希函数为:H(key)= key  %  11,则H(47)=3,H(26)=4,H(60)=5,假设下一个关键字为69,则H(69)=3,与47冲突。

如果用线性探测再散列处理冲突,下一个哈希地址为H1=(3 + 1)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 + 2)% 11 = 5,还是冲突,继续找下一个哈希地址为H3=(3 + 3)% 11 = 6,此时不再冲突,将69填入5号单元。

如果用二次探测再散列处理冲突,下一个哈希地址为H1=(3 + 12)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 - 12)% 11 = 2,此时不再冲突,将69填入2号单元。

如果用伪随机探测再散列处理冲突,且伪随机数序列为:2,5,9,……..,则下一个哈希地址为H1=(3 + 2)% 11 = 5,仍然冲突,再找下一个哈希地址为H2=(3 + 5)% 11 = 8,此时不再冲突,将69填入8号单元。

从上述例子可以看出,线性探测再散列容易产生“二次聚集”,即在处理同义词的冲突时又导致非同义词的冲突。例如,当表中i, i+1 ,i+2三个单元已满时,下一个哈希地址为i, 或i+1 ,或i+2,或i+3的元素,都将填入i+3这同一个单元,而这四个元素并非同义词。线性探测再散列的优点是:只要哈希表不满,就一定能找到一个不冲突的哈希地址,而二次探测再散列和伪随机探测再散列则不一定。

2.再哈希法

这种方法是同时构造多个不同的哈希函数:

          Hi=RH1(key),i=1,2,3,…,n.

当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

3.链地址法

这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。链地址法适用于经常进行插入和删除的情况。

拉链法的优点

与开放定址法相比,拉链法有如下几个优点:

  • (1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
  • (2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
  • (3)开放定址法为减少冲突,要求装填因子α(装填因子=表中的记录数/哈希表的长度)较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
  • (4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。而对开放地址法构造的散列表,删除结点不能简单地将被删结点的空间置为空,否则将截断在它之后填入散列表的同义词结点的查找路径。这是因为各种开放地址法中,空地址单元(即开放地址)都是查找失败的条件。 因此在用开放地址法处理冲突的散列表上执行删除操作,只能在被删结点上做删除标记,而不能真正删除结点。

拉链法的缺点

拉链法的缺点是:指针需要额外的空间,故当结点规模较小时,开放定址法较为节省空间,而若将节省的指针空间用来扩大散列表的规模,可使装填因子变小,这又减少了开放定址法中的冲突,从而提高平均查找速度。

4.建立公共溢出区

这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表.(注意:在这个方法里面是把元素分开两个表来存储)

冲突太多了怎么办?

当冲突太多的时候,我们一般采用的方法时拉链法,采用拉链法的原因是动态申请空间,至于优点在上面已经阐述了.冲突太多的时候会产生堆积状态,我们将H(key)相同的关键字都统一放到一个链里,当出现冲突的时候我们就把该元素接在链表后面,这样可以避免产生堆积现象,缩短平均查找长度.

当数据表太小,而数据太多的时候怎么办?

当数据表太小数据太多可以通过建立一个溢出表,专门用来存放哈希表中放不下的记录.


Hash表的平均查找长度

Hash表的平均查找长度包括查找成功时的平均查找长度和查找失败时的平均查找长度。

查找成功时的平均查找长度=表中每个元素查找成功时的比较次数之和/表中元素个数;

查找不成功时的平均查找长度相当于在表中查找元素不成功时的平均比较次数,可以理解为向表中插入某个元素,该元素在每个位置都有可能,然后计算出在每个位置能够插入时需要比较的次数,再除以表长即为查找不成功时的平均查找长度。

下面举个例子:

有一组关键字{23,12,14,2,3,5},表长为14,Hash函数为key%11,则关键字在表中的存储如下:

          地址     0     1     2     3      4     5    6   7   8    9  10   11   12    13

          关键字        23    12   14     2     3    5

          比较次数         1      2    1     3     3     2

因此查找成功时的平均查找长度为(1+2+1+3+3+2)/6=11/6;

查找失败时的平均查找长度为(1+7+6+5+4+3+2+1+1+1+1+1+1+1)/14=38/14;

这里有一个概念装填因子=表中的记录数/哈希表的长度,如果装填因子越小,表明表中还有很多的空单元,则发生冲突的可能性越小;而装填因子越大,则发生冲突的可能性就越大,在查找时所耗费的时间就越多。因此,Hash表的平均查找长度和装填因子有关。有相关文献证明当装填因子在0.5左右的时候,Hash的性能能够达到最优。因此,一般情况下,装填因子取经验值0.5(也就是说所需的实际空间为元素数目的2倍)

Hash表大小的确定也非常关键,如果Hash表的空间远远大于最后实际存储的记录个数,则造成了很大的空间浪费,如果选取小了的话,则容易造成冲突。在实际情况中,一般需要根据最终记录存储个数和关键字的分布特点来确定Hash表的大小。还有一种情况时可能事先不知道最终需要存储的记录个数,则需要动态维护Hash表的容量,此时可能需要重新计算Hash地址。


参考:
http://www.cnblogs.com/vamei/archive/2013/03/24/2970339.html
http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html
http://zh.wikipedia.org/wiki/%E5%93%88%E5%B8%8C%E8%A1%A8
http://en.wikipedia.org/wiki/Hash_table
http://blog.csdn.net/jirongzi_cs2011/article/details/9377779
http://blog.csdn.net/liangbopirates/article/details/9753599

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292786.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国已消失的九所世界级大学

全世界只有3.14 % 的人关注了爆炸吧知识众所周知&#xff0c;我们国家的大学数量在世界范围内数一数二&#xff0c;但是有很多赫赫有名的大学却在历史中被人们遗忘&#xff0c;下面我们一起回顾一下那些不该被忘记的大学。>>>>▌燕京大学燕京大学&#xff08;Yench…

IOS Table中Cell的重用reuse机制分析

2019独角兽企业重金招聘Python工程师标准>>> 解决代码&#xff1a; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *CellIdentifier [NSString stringWithFormat:"Cell%d%d", …

子商城管理之签到活动

--建表脚本: --create sequence create sequence SIGN_ACTIVITY_SEQ;-- Create table create table SIGN_ACTIVITY (SIGN_ACTIVITY_ID NUMBER not null,START_TIME VARCHAR2(20),END_TIME VARCHAR2(20),ACTIVITY_INTRODUCTION VARCHAR2(300),REWA…

VS2017/2019 F12无法导航到定义

今天对项目里某个对象点F12转到定义&#xff0c;无法跳转,研究了一会儿&#xff0c;找到如下解决方案:首先确认该函数是否能够正确被跳转到..就是是否真实定义了&#xff0c;然后确保要跳转的定义源码在项目文件下&#xff08;而不是直接引用的DLL&#xff09;接下来关闭VS2017…

oracle 主键删除,联合主键的创建

1&#xff0c;主键的删除 ALTER TABLE TABLENAME DROP PRIMARY_KEY运行上面的SQL能够删除主键&#xff1b;假设不成功能够用ALTER TABLE TABLENAME DROP CONSTRAINTS COLUMN CASCADE; --删除约束ALTER TABLE TABLENAME DISABLE PRIMARY_COLUMN ; --设置被设置为主键的列为无效D…

unable to launch什么意思_都表示太...以至于,so … that…?与too… to …有着明显区别...

【2019年12月8日 百天英语-Day135】【华东师范大学-林森撰写】昨日内容复习提要&#xff1a;昨天学习了主要学习了 ①be able to …与can的区别。②如何通过不认识的单词&#xff0c;猜到作者表达的含义。昨天文章如下&#xff1a;表示有能力做某事&#xff0c;be able to …与…

数据结构-Hash总结(一):理论学习篇

转载请注明出处http://blog.csdn.net/yankai0219/article/details/8185796零、学习方法简要学习理论篇&#xff0c;进入程序学习篇&#xff0c;再回头学习理论篇和实践篇一、基本概念1.Hash定义Hash定义&#xff1a;将任意长度的输入&#xff0c;通过散列算法&#xff0c;变成固…

Prism For WPF Login对话框又简单又合理的方案之一

一、前言 这是一篇极简的小短文。首先感谢站长和各位WPF大佬对我的指导&#xff0c;我学到了很多&#xff0c;还是关于利用Prism做Login对话框的事情&#xff0c;看到站长发过一篇《WPF Prism框架Region失效了&#xff1f;》&#xff0c;目前我有一个自认为更合适的解决方法&am…

html5 的支持

html5.js让IE&#xff08;包括IE6&#xff09;支持HTML5元素方法 微软的最新浏览器IE8及以下IE版本对HTML5标签的支持是有限的&#xff0c;我们可以通过在网页中添加脚本的方式来解决目前IE浏览器对HTML5支持的问题。 让IE&#xff08;包括IE6&#xff09;支持HTML5元素&#x…

求指教、。。。关于调用so文件

问题描述今天同事给我发来一个文件&#xff0c;说让我通过android调用里面的函数文件是&#xff1a;里面的内容是&#xff1a;call_so.cpp文件的内容&#xff1a;#pragma pack(1) //非常重要的申明&#xff0c;内存对齐的方法&#xff0c;影响sizeof()的结果#include <stdio…

数据结构-Hash总结(三):实践基础篇

转载请注明出处 http://blog.csdn.net/yankai0219/article/details/8185847问题&#xff1a;1. hash算法主表实现为什么不直接用数组,而使用malloc动态申请?2. 另外每个桶的使用 线性队列 和 双向队列 以及 二级hash的区别以及好处是什么?答案:1.1&#xff09;hash表大小如果…

人类历史上最伟大的物理学家

全世界只有3.14 % 的人关注了爆炸吧知识一沙见世界 一花窥天堂手心握无限 须臾纳永恒杨振宁曾说读上面的四句诗可以感受到物理的美但物理的美不止于此物理还有一种庄严美一种神秘美一种初窥宇宙奥秘的畏惧美物理就是如此的迷人任何语言在它的面前都很贫瘠数学让人摆脱了愚昧而…

DevToys - 开发人员的瑞士军刀

DevToys 是一个适用于开发人员的工具箱, 基于 UWP 开发, DevToys 旨在拥抱 Windows 生态系统, 免费并且开源, 拥有现代化的界面, 支持中文, 有深色/浅色主题可选, 并且它是离线化的, 所以你完全可以在无网络环境中使用。你可以使用它处理与开发相关的一些任务, 它提供 了14…

python写小猪佩奇_python之小猪佩奇

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 小猪佩奇 &#xff08;源码有点长&#xff09;# coding:utf-8 import turtle as t t.pensize(4) t.hideturtle() t.colormode(255) t.color((255,155,192),"pink") t.setup(840,500) t.speed(10) #鼻子 t.pu() t.goto(-…

PYHON中的切片

Python中的切片容易混淆&#xff0c;这里总结一下自己的看法 切片的语法 1 a [1,2,3,4] 2 x a[1:2] #实际上执行的是 a.__getitem__(slice(1,2,None)) 1 slice([start], stop[, step] 2 3 step的符号表示一种方向的含义 4 &#xff1a;从左向…

求字符串的不重复字符的最长子串长度的问题

题目: 已知一个字符串,只含有小写字母,求这个字符串的每个字符都不相同的最长子串的长度。 比如: abcd 结果是4 abcab 结果是3 思路: 用一个26个元素的整形数组表示一个字符串中是否含有某个字符。a~b分别映射到数组元素0~25。 用两个指针分别指向字符串的第一个和第…

ionic 中文 API CSS and javascript link

ionic 中文 API CSS ionic 中文 API javascript 转载于:https://www.cnblogs.com/xieyier/p/4036152.html

phpmyadmin的安装部署

系统环境&#xff1a;centos7php版本&#xff1a;5.3.27phpmyadmin版本&#xff1a;4.2.7.1IP:192.168.1.205数据库&#xff1a;mysql5.5.32本次部署使用nginx下载phpmyadmin&#xff1a;wget https://files.phpmyadmin.net/phpMyAdmin/4.2.7.1/phpMyAdmin-4.2.7.1-all-languag…

你和985硕博研究生,差了这些东西

全世界只有3.14 % 的人关注了爆炸吧知识明明都是在搞科研为什么别人的思路比你开阔&#xff1f;明明都是在写文章为什么别人的方向比你更新颖&#xff1f;今天小编就来推荐几个能拓展视野的公号快点收藏起来吧&#xff01;募格课堂ID&#xff1a;mugeketang推荐理由&#xff1a…