数据结构与算法之美(笔记9)哈希算法

什么是哈希算法?

我们前面讲到散列表,散列函数,这里又是哈希算法,实际上,散列函数就是哈希算法的一个特例。只不过在散列表中,我们通常希望散列函数简单,才不会影响查找等的性能。哈希算法的定义和原理很简单,就是把任意二进制串值映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始的数据映射之后得到的二进制值串就是哈希值。

哈希算法满足的几点要求:

  • 从哈希值不能反向推导出原始数据。
  • 对输入的数据非常敏感,哪怕原始数据只修改了一个bit,最后得到的哈希值也大不相同。
  • 散列冲突的概率要小,对于不同的原始数据,哈希值相同的概率很小。
  • 哈希算法的执行效率要尽量高效,针对长的文本,也能快速计算出哈希值。

应用一:安全加密

最常用的加密算法是MD5,和SHA。对用于加密的哈希算法来说,有两点格外重要。第一点是很难根据哈希值反向推导出原始数据,第二点是散列冲突的概率很小。

实际上,不管是什么哈希算法,我们只能尽量减少碰撞冲突的概率,理论上是没有办法做到完全不冲突的。这里基于组合数学一个非常基础的理论,鸽巢原理。如果有10个鸽巢,有11只鸽子,那肯定有一个鸽巢中的鸽子数量多于1个。

同样的,哈希算法产生的哈希值的长度是固定且有限的。比如前面的MD5算法,哈希值是固定的128位,能表示的数据是有限的,但是我们要哈希的数据是无穷的,基于鸽巢原理,如果我们对2^128+1个数据求哈希值,就必定会存在一个哈希值相同的情况。一般情况下,哈希值越长的哈希算法,散列冲突的概率越低。

不过,即使哈希算法存在散列冲突的情况,但是因为哈希值的范围很大,冲突的概率很低,所以相对来说还是很难破解的。

应用二:唯一标识

举个例子,如果要在海量的图库中,搜索一张图是否存在,我们不能单纯地用图片的原信息(比如图片名称)来对比,因为有可能存在名称相同但图片名称不同,或者名称不同图片内容相同的情况。

我们知道,任何文件在计算中都可以表示成二进制码串。我们可以给每一个图片取一个唯一标识或者说是信息摘要。我们可以从图片的二进制串开头取100个字节,从中间取100个字节,从最后取100个字节,然后将这300个字节放到一起,通过哈希算法,得到一个哈希字符串,用它来做图片的唯一标识。通过这个唯一标识来判定图片是否在图库中,这样就可以减少很多工作量。

如果还想继续提高效率,我们可以以唯一标识作为key,相应的图片文件在图库中的路径信息作为value,构建一个散列表。当要查看某个图片是否在图库中的时候,我们先通过哈希算法对这个图片取唯一的标识,然后在散列表中查找。

假设我们使用链表法来解决冲突,我们通过一张图片取唯一标识,经过散列函数得到数组下标,看这个槽中的唯一标识是否相同,如果不相同,则说明不存在,如果相同,为了提高准确率,我们在利用散列表中储存的文件标识,进行全图比对。

应用三:数据校验

我们知道,BT下载的原理是基于p2p协议的。我们从多个机器上并行下载一个2GB的电影,这个电影文件可能会被分割成很多文件块,等所有的文件都下载完成之后,再组装成一个完整的电影文件就行了。

我们知道,网络传输是不安全的,下载的文件块有可能是被宿主机器恶意修改过的,又或者下载过程中出现了错误,所以下载的文件块可能不是完整的。如果这个时候我们下载了,有可能导致电影无法观看,或者电脑中毒。

其中的一个思路是:我们通过哈希算法,对分割出来的文件块分别取哈希值,并且保存在种子文件中。我们在前面讲过,哈希算法有一个特点,对数据很敏感。只要文件块的内容有一点儿的改变,最后计算出的哈希值就会完全不同。所以,当文件块下载完成之后,我们可以通过相同的哈希算法,对下载好的文件块逐一哈希值,然后跟种子文件保存的哈希值比对。如果不对,就说明文件不完整或者被篡改了。

应用四:负载均衡

如何实现一个会话粘滞的负载均衡算法?也就是说,我们需要在同一个客户端上,在一次会话中的请求都路由到同一个服务器上。如我们可以通过哈希算法,对客户端ID地址或者会话ID计算哈希值,将取得的哈希值与服务器列表的大小进行取模运算,最终得到的值就是应该被路由到的服务器端号。这样,我们就可以把同一个IP过来的所有请求,都路由到同一个后端服务器上。

应用五:数据分片

假设我们的图库有1亿张图片,显然,在单台机器上构建散列表是行不通的。因为单台机器的内存有限,而1亿张图片构建散列表显然远远超过了单台机器的内存上限。

我们可以对数据进行分片,然后采用多机处理。我们准备n台机器,让每台机器只维护某一部分图片对应的散列表。我们每次从图库中读取一个图片,计算唯一标识,然后与机器个数n求余取模,得到的值就是要对应要分配的机器编号,然后将这个图片的唯一标识和图片的路径发往相应的机器构建散列表。

当我们要判断一个图片是否在图库的时候,我们通过同样的哈希算法,计算这个图片的唯一标识,然后与机器个数n求余取模,假设我们得到的是K,然后我们就去编号为k的机器构建的散列表中查找。

实际上,针对这种海量数据的处理问题,我们都可以采用多机分布式处理。借助这种分布的思路,可以突破单机内存,cpu等资源的限制。

应用六:分布式存储

对于海量的数据,海量的用户。我们为了提高数据的读取,写入能力,一般都采用分布式的方式来存储数据,比如分布式缓存,如果有海量的数据需要缓存,一个缓存机器肯定不够,于是,我们就需要将数据分布到多台机器上。

我们可以借用前面的数据分片的方法,通过哈希算法对数据计算哈希值,得到机器编号。但是如果数据增多,这10个机器不够了怎么办?这里就不是加一个机器那么简单了,因为所有的数据都需要重新计算哈希值。这个时候,我们需要一种方法,使得再加入一个机器后,并不需要大量的数据搬移。这个时候,我们需要使用一致性哈希算法。

假设我们有k个机器,数据的哈希值的范围是[0,max],我们将整个范围划分为M个小的区间(m远大于k),每个机器负责m/k个小区间。当有先机器加入的时候,我们就将某几个小区间的数据,从原来的机器搬移到新的机器上。这样就不用全部重新计算并且搬移了。

猜你喜欢

转载自blog.csdn.net/weixin_42073553/article/details/88683099
今日推荐