哈希(哈希表与哈希函数)

、哈希

哈希函数是计算机领域特别是在密码学领域应用最广泛的算法之一,哈希表是数据结构中应用最广泛的结构之一,本博客将为大家介绍哈希函数,介绍哈希表。

1、哈希函数

2、哈希表

3、哈希函数在大数据中应用

1.1哈希函数

哈希函数的性质

哈希函数又名散列函数,对于经典哈希函数来说,它具有以下5点性质:

1、输入域无穷大

2、输出域有穷尽

3、输入一样输出肯定一样

4、当输入不一样输出也可能一样(哈希碰撞)

5、不同输入会均匀分布在输出域上(哈希函数的散列性)

这里对第5点做一些解释,例如输入域是0-99这一百个数字,而我们使用的哈希函数的输出域为0,1,2,当我们将0-99这一百个数字通过该哈希函数,得到的返回值,0,1,2数量都会接近33个,不会出现某个返回值数量特别多,而某个返回值特别少。

这里需要注意的是,对于哈希函数来说,有规律的输入并不能得到有规律的输入,例如十个1Mb的字符串,只有最后1bytes的内容不一样,在经过哈希函数后得到返回值千差万别,而不会有规律,所以它可以来打乱输入规律。

通常哈希函数的输出域都很大(相对于输入域很小),例如常见的MD5(Message Digest Algorithm (中文名为消息摘要算法第五版))算法,它的输出域是0到2^64-1,但是往往我们都会将哈希函数的返回值模上一个较小的数m,让哈希函数的输出域缩减为0到m-1.

如何生成多个哈希函数

这里我们介绍一种快速生成多个哈希函数的方法。

假如你急需要1000个哈希函数,并且这1000个哈希函数都要求相互独立,不能有相关性。这时,错误的方法是去在网上寻找1000个哈希函数。我们可以通过一个哈希函数来生成这样的1000个独立的哈希函数。

假如,你有一个哈希函数f,它的输出域是2^64,也就是16字节的字符串,每个位置上是16进制的数字0-9,a-f。

我们将这16字节的输出域分为两半,高八位,和低八位是相互独立的(这16位都相互独立)。这样,我们将高八位作为新的哈希函数f1的输出域,低八位作为新的哈希函数f2的输出域,得到两个新的哈希函数,它们之间相互独立。

故此可以通过以下算式得到1000个哈希函数:

f1+2*f2=f3
f1+3*f2=f4
f1+3*f2=f5
……

这里可以通过数学证明f3与f4及以后的哈希函数不相关,数学基础较好的同学可以查询相关资料,尝试证明,这里就不给出具体的证明了。

1.2哈希表

哈希表的经典结构

在数据结构中,哈希表最开始被描述成一个指针数组,数组中存入的每个元素是指向一个链表头部的指针。

我们知道,哈希表中存入的数据是key,value类型的,哈希表能够put(key,value),同样也能get(key,value)或者remove(key,value)。当我们需要向哈希表中put(插入记录)时,我们将key拿出,通过哈希函数计算hashcode。假设我们预先留下的空间大小为16,我们就需要将通过key计算出的hashcode模以16,得到0-15之间的任意整数,然后我们将记录挂在相应位置的下面(包括key,value)。

注意:位于哪个位置下只与key有关,与value无关

例如我们要将下面这样一条记录插入哈希表中:


“shiyanlou”,666 #key是shiyanlou,value是666

首先我们通过哈希函数,计算shiyanlou的hashcode,然后模以16。假如我们得到的值是6,哈希表会先去检查6位置下是否存在数据。如果有,检查该节点中的key是否等于shiyanlou,如果等于,则将该节点中的value替换为666;如果不等于,则在链表的最后新添加一个节点,保存我们的记录。

由于哈希函数的性质,得到的hashcode会均匀分布在输出域上,所以模以16,得到的0-15之间的数目也相近。这就意味着我们哈希表每个位置下面的链表长度相近。

对于常见的几种数据结构来说,数组的特点是:容易寻址,但是插入和删除困难。而链表的特点是:寻址困难,但是插入和删除容易。而对于哈希表来说,它既容易寻址,同样插入和删除容易,这一点我们从它的数据结构中是显而易见的。

在实际哈希表应用中,它的查询速度近乎O(1),这是因为通过key计算hashcode的时间是常数项时间,而数组寻址的时间也是常数时间。在实际应用中,每个位置的链表长度不会太长,当到达一定长度后,哈希表会经历一次扩容,这就意味着遍历链表的时间也是常数时间。

所以,我们增删改查哈希表中的一条记录的时间可以默认为O(1)。

1.3 哈希函数在大数据中的应用

例如,我们有一个10TB的大文件存在分布式文件系统上,存的是100亿行字符串,并且字符串无序排列,现在我们要统计该文件中重复的字符串。

假设,我们可以调用100台机器来计算该文件。

那么,现在我们需要怎样通过哈希函数来统计重复字符串呢。

首先,我们需要将这一百台机器分别从0-99标好号,然后我们在分布式文件系统中一行行读取文件(多台机器并行读取),通过哈希函数计算hashcode,将计算出的hashcode模以100,根据模出来的值,将该行存入对应的机器中。

根据哈希函数的性质,我们很容易看出,相同的字符串会存入相同的机器中。

然后我们就能并行100台机器,各自分别计算相应的数据,大大加加快统计的速度。

注意:这10TB文件并不是均分成100GB,分给100台机器,而是这10TB文件中不同字符串的种类,均分到100台机器中。如果还嫌单个机器处理的数据过大,可以按照同样的方法,在一台机器中并行多个进程,处理数据。



猜你喜欢

转载自blog.csdn.net/qq_38180223/article/details/80911868