最小完美哈希函数(深入搜索引擎)

合集下载

完美hash算法

完美hash算法

完美hash算法完美哈希算法哈希算法是计算机科学中常用的一种算法,用于将输入数据映射到固定大小的值。

在哈希算法中,如果两个不同的输入数据生成了相同的哈希值,就称为哈希冲突。

完美哈希算法是一种能够解决哈希冲突问题的特殊算法,它能够在保证哈希值唯一性的同时,尽可能地减少冲突的发生。

完美哈希算法的核心思想是通过精心设计的哈希函数,将输入数据直接映射到哈希表中的某个位置,而无需通过遍历来查找。

这样一来,即使存在大量的数据,也能够快速地定位到目标数据,提高了算法的效率。

完美哈希算法的设计有很多种方法,下面介绍一种常用的方法——基于二次哈希的完美哈希算法。

我们需要确定哈希表的大小,一般选择一个合适的质数作为表的大小,这样能够更好地分散数据,减少冲突的概率。

接下来,我们需要设计两个哈希函数,一个用于计算第一次哈希值,另一个用于计算第二次哈希值。

第一次哈希函数将输入数据映射到哈希表的某个位置,产生一个中间结果。

然后,根据这个中间结果,再通过第二次哈希函数计算最终的哈希值。

如果第一次哈希函数的结果发生了冲突,那么我们就需要重新选择另一个哈希函数,直到找到一个不冲突的哈希函数为止。

在选择哈希函数时,我们可以考虑一些常用的方法,比如使用乘法和除法等运算,结合取模操作,将输入数据映射到哈希表的某个位置。

同时,我们还可以根据实际的数据分布情况,对哈希函数进行优化,以进一步减少冲突的概率。

完美哈希算法的优点是能够在保证哈希值唯一性的同时,具有较高的查询效率。

由于哈希值的计算是通过一次哈希函数和一次取模操作完成的,所以算法的时间复杂度为O(1),即不受数据量大小的影响。

这使得完美哈希算法在大规模数据处理和高性能计算等领域具有广泛的应用价值。

然而,完美哈希算法也存在一些限制和挑战。

首先,设计一个完美哈希算法需要耗费大量的时间和精力,需要对数据进行充分的分析和理解。

其次,完美哈希算法对输入数据的格式和分布有一定的要求,如果数据的分布不均匀或者数据格式发生变化,可能会导致冲突的发生。

c语言哈希库函数

c语言哈希库函数

c语言哈希库函数C语言哈希库函数哈希函数是一种将输入数据映射为固定大小值的函数,常用于数据的索引和加密等领域。

在C语言中,哈希库函数提供了一系列实现不同哈希算法的函数,方便开发者在自己的程序中使用哈希功能。

本文将介绍C语言中常见的哈希库函数及其使用方法。

一、哈希函数的作用和原理哈希函数是将任意长度的输入数据映射为固定长度的输出值,这个输出值被称为哈希值或散列值。

哈希函数的作用是为了快速在数据集中定位和识别特定的数据。

哈希函数的原理是将输入数据通过一系列的计算和映射操作,最终得到一个固定长度的输出值。

哈希函数应该具备以下特点:1. 输入数据的任意变化都能导致输出值的不可预测变化;2. 相同的输入始终得到相同的输出;3. 输入数据的微小变化也将导致输出值的较大变化,即具有雪崩效应;4. 难以通过哈希值反推出原始输入数据。

二、C语言中常见的哈希库函数1. MD5(Message Digest Algorithm 5)MD5是一种广泛使用的哈希算法,可以将任意长度的数据转换为128位的哈希值。

在C语言中,可以使用openssl库中的MD5函数来计算MD5哈希值。

```c#include <openssl/md5.h>#include <stdio.h>#include <string.h>int main() {const char* input = "Hello World";unsigned char output[MD5_DIGEST_LENGTH];MD5((unsigned char*)input, strlen(input), output);printf("MD5 Hash: ");for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {printf("%02x", output[i]);}printf("\n");return 0;}```2. SHA-1(Secure Hash Algorithm 1)SHA-1是一种安全性较高的哈希算法,可以将任意长度的数据转换为160位的哈希值。

适用于高速检索的完美Hash函数

适用于高速检索的完美Hash函数

适用于高速检索的完美Hash函数王兴;鲍志伟【摘要】软件实现的Hash函数在当前检索领域应用非常广泛,但是由于处理速度不高,很难满足骨干网以及服务器海量数据的高速实时查找要求.硬件Hash函数处理速度快,但普遍存在设计电路复杂、存储空间利用率不高以及无法支持数据集动态更新等问题.基于位提取(Bit-extraction)算法,利用位选择(Bit-Selection)操作与位逻辑运算在FPGA上仿真实现一种Hash函数,可生成负载因子(Load factor)接近于1的近似最小完美Hash表.仿真结果表明,该Hash函数中每个24 bits长度Key的存储空间只要2.8-5.6 bits,系统时钟频率可以达到300MHz左右(吞吐率超过14Gbps).可以应用于IP地址查找、数据包分类、字符串匹配以及入侵检测等需要实时高速表查找的场景.【期刊名称】《计算机系统应用》【年(卷),期】2016(025)002【总页数】7页(P250-256)【关键词】硬件Hash表;完美Hash函数;高速搜索;最小完美Hash表【作者】王兴;鲍志伟【作者单位】浙江广厦建设职业技术学院信息与工程控制学院,东阳322100;香港城市大学电子工程系,香港;香港城市大学电子工程系,香港【正文语种】中文假设数据集{〈ki,vi〉| 1 ≤ i ≤ N},由N 条记录组成,其中ki是第i条Key,vi是与该Key对应的Value值. 令Key的集K = {ki| 1 ≤ i ≤ N},构造Hash表时,通过Hash 函数F将K映射成从0到m-1的整数,即F(K)→{0,1,2,…,m-1},那么0到m-1就是生成的Hash表T的地址,vi就保存在T[F(ki)]上. m为Hash表的大小,m≥ N,衡量Hash表存储空间利用率的负载因子(Load factor)λ=N/m. 如果存在两个不同的ki 和kj,通过F映射后存在F(ki) = F(kj),那么说明存在Hash冲突,这将影响到Hash表的查找性能. 往往λ越大,Hash冲突的可能性就越大. 不存在冲突的Hash函数叫完美Hash函数,负载因子λ=1的完美Hash函数叫最小完美Hash函数.Hash函数通过输入的Key直接读取得到对应的Value,保证搜索算法的平均时间复杂度为O(1),可以大大提高了表搜索效率,所以在互联网搜索领域应用非常广泛,比如在深度包检测(Deep packet inspection)[1]、路由表查找[2]、数据包分类[3]、高速入侵检测[4]以及模式匹配[5]等方面. 基于软件实现的Hash函数处理速度很难满足高速实时的查找要求,硬件Hash函数的查找速度往往可以达到1Gb/s以上,但是适用于几十万特别是百万级别数据集的高速硬件Hash函数的设计在当前计算机领域还存在一些困难,包括设计电路复杂、运算速度慢、Hash冲突频繁、不支持动态更新等. 特别是由于FPGA芯片的存储空间成本很高,比如Xilinx较新的Virtex-6产品系列只有4.5MB可用的存储空间,要在硬件上设计支持大数据集的Hash函数,在保证处理速度的前提下,如何提高存储资源利用率是当前的一个最大挑战.本文针对以上问题,基于位提取(Bit-extraction)算法,利用位选择(Bit-Selection)操作与位逻辑运算,在FPGA上实现一种完美Hash函数. 用120K到480K大小的静态和动态数据集分别进行测试表明,该Hash函数每个24 bits长度Key的存储空间只要2.8-5.6 bits,系统时钟频率可以达到300MHz左右,吞吐率大于14Gbps,生成的Hash表负载因子可以接近于1. 具有硬件设计电路简单、资源消耗低,Hash表查找速度快、存储空间利用率高等特点,适用于各种需要高速实时表查找的应用.硬件实现的Hash函数研究工作主要集中在解决Hash冲突方面,最常见的方法[6]就是利用已知的数据集构建独特专用的Hash函数,实现完美Hash表. Cuckoo hashing[7]是一个非常经典且原理简单的Hash算法,利于硬件实现,但是允许达到的最大负载因子是0.5. 该算法利用两个Hash表T1和T2,以及两个Hash函数F1和F2来处理Hash冲突. 对于输入的任意一个Key ki,都可以两个可能的存储位置T1[F1(ki)] 和T2[F2(ki)]. 构建Hash表时,如果Key ki对应的2个位置中有一个为空,ki就可以插入到那个位置. 否则,任选一个位置将ki插入,并把已经在那个位置的Key踢出来. 被踢出来的Key需要重新插入,不断递归循环,直到没有Key被踢出为止. 当陷入无限循环时,则需要重新选择Hash函数. 增加Hash函数的个数或者在每个Hash表地址空间存储多个Key,可以提高Cuckoo hashing表的负载因子. FICARA[8]等人通过引入外部区分表实现完美Hash函数. 在查表操作过程中,首先读取外部区分表中的当前Key对应的区分位,然后将区分位合并到当前Key后再进行Hash函数求值. 1K大小的数据集中每个Key占用外部区分表的空间大概是2-4 bits. 这种方法主要的缺点是构建外部区分表很耗时,而且不支持新的Key的动态插入. KUMAR[9]以及ISTVÁN[10]等人通过采用类似于链接的数据结构,增加Hash 表每个相同Hash地址对应存储空间里value的个数,降低Hash冲突. 该类方法支持的数据集大小比较有限,而且不能保证持续稳定的读取速度. Hash表的容量都是有限的,插入新的Key时,肯定有溢出发生的可能. BANDO[11]等人利用片内内容寻址存储器(Content Addressable Memory,CAM)作公共溢出缓存区,降低插入时Hash冲突概率,改善Hash表最坏访问时间的问题.Bloom Filter (BF)[12]可以有效地确认输入的Key是否是某个数据集的成员,但是BF算法本身存在误判率. 如果将BF算法在硬件上实现,并把误判率控制在0.1%以下,则每个Key的存储空间大概需要14.5 bits. 另外,BF算法只能判断输入的Key 是否属于某个数据集,但是无法对该Key进行区分. 针对此问题,很多研究对BF算法进行了扩展[13,14],可以对匹配到的Key进行准确的区分,但是硬件实现后每个Key 需要50 bits左右的存储空间,而且负载因子仅为0.25左右.本文提出的硬件Hash函数的基本设计思路就是利用基于贪心法则(Greedy Approach)的Bit-Extraction算法,对已知数据集中的Key(二进制)提取几个位作为特殊位. 根据特殊位进行位选择操作,将原始的Key集分成一系列子集,通过位运算操作生成Hash表地址,实现快速的Hash表查找.本设计的Hash函数硬件框图如图1所示,可以分成三级的流水结构. 第一级是用第一个位选择操作,将定长为L的二进制Key分成长度分别为LA的A与长度为LB(LB=L-LA)的B. 在常见的应用场景中,Key的长度L一般在16bits到64bits之间. 假设数据集的大小为N,即Key的个数为N,则我们计算A的长度LA≈[log2N/64]. 用A作为查找表(Lookup Table)T1的地址,读取存储在表中相应位置的bit_index. 在第二级位选择操作中,利用2个位索引bit_index将B分成长度为2bits的B0和长度为(LB-2)的B1. 然后,将A和B0合并后的{A,B0}作为查找表T2的地址,读取存储在表中相应位置的位掩码mask,块占有向量blk_vec以及基础地址base. 最后利用mask,blk_vec与B1计算出地址位移offset,而{base+offset}就是我们所要得到Hash表地址hash_addr. 以上的整个过程,也可以看作是Hash算法的设计过程.为了方便理解,我们选择一个长度L为20bits的Key集作为例子说明. 如表1所示,在第一个位选择操作中,将标注深灰的9个特殊位选择作为A,剩余的作为B,则LA=9,LB=11. 本例中A均为0-0000-0000,即所有Key都映射到了T1[0],假设读出存储在T1[0]的bit_index值为3,0. 根据bit_index的值,在第二个Bit-Selection操作中,选择第0位和第3位的B值(浅灰标注)作为B0,剩余的作为B1. 将A与B0合并成{A,B0}作为地址读取T2,获得存储在表中相应位置的mask,blk_vec以及base的值. mask的长度与B1的长度相同,mask中所有值为1的位对应的B1的值就是offset. 我们在设计中用8bits的blk_vec来提高Hash 表的负载因子. 每一个相同T2地址对应的Hash表存储区域称为块,如果块内记录数等于2n,n为offset的位数(mask中位值为1的个数),那么表示该块已经被全部利用,blk_vec的位值全设为0;否则表示块只是部分被利用,被利用的块对应的位的值设为1,其它位设为0. 比如T2的地址为{A,B0}=000-0000-0001对应Hash表中的块包含e,f,g三个项的值,对应的2位的offset分别为01,00,11,很明显,offset 值为10对应的Hash表存储区域没有被利用,所以它存储在表T2对应的blk_vec 为0000-1011,如表2所示. 在对Hash表进行插入操作的时候,可以根据blk_vec 的值,调整新插入的Key的offset值,将其插入到Hash表中空余区域,实现支持新Key动态插入,同时提高Hash表负载因子.3.1 Bit-Extraction算法在Hash函数硬件实现之前,要利用Bit-Extraction算法预先处理原始Key集,从已知数据集中的Key提取m个位作为特殊位,将数据集分成一系列子集,并得出位掩码mask. Bit-Extraction算法利用贪心法则,根据选择成本cost尽可能地平衡子集的大小. 给定一个数据集大小为N,Bit-Extraction算法先计算出每个位中位值为"1"的Key的个数以及位值为"0"的Key的个数,如果第i位值为"1"的Key的个数为ni,那么通过选择第i位作为特殊位将把数据集分成大小分别为ni和(N-ni)的两个数据集,选择成本cost为min(ni,N-ni). 从Key中选择成本cost值的和最大的LA个位作为A,剩余的位作为B. Bit-Extraction算法基本思想用伪代码描述如下: 输入: u个长度为k的key构成的数据集p[0…u-1]输出: 选择的m个特殊位与掩码mask,子Group1: group_size[0] = u; //初始时所有的key都放在group 02: for (s = 0; s < m; s++) //每一次循环迭代选择一个特殊位3: { for (i = 0; i < u; i++)4: for (j = 0; j < k; j++)5: if (j-th bit of p[i] == 1)6: cost[p[i].group][k]++; //求出每一个位对应的cost值7: for (i = 0; i < pow(2,s); i++):8: for (j = 0; j < k; j++)9: if (cost[i] > group_size[i] - cost[i]):10: cost[i] = group_size[i] - cost[i];//选择小的值作为cost11: for (i = 1; i < pow(2,s); i++) //把子集中所有的cost值相加,找出cost最大和,求出相应选择的位和mask12: cost[0]+=cost[i];13: max_cost = cost[0][k-1];14: selected_bit = k-1;15: for (j = k-2; j >= 0; j--)16: if (cost[0] > max_cost)17: { max_cost = cost[0];18: selected_bit = j;19: }20: if (max_cost == 0) 直接选择最右的位,break; //无需继续迭代21: 将选择位的mask值设为1;22: if (s < m-1) 为下一次迭代更新变量; }用C语言实现Bit-Extraction算法程序,在配置为Intel Core2 6400 CPU@2.13GHz,Window XP 操作系统的计算机上运行测试,得出只需要5s左右就可以对大小约为500K,长度为32bits的数据集构建本Hash函数中所需的数据内容.3.2 硬件设计实现本文的完美Hash函数在FPGA上设计实现,第一个位选择操作对长度为L的Key 通过L个多路复用器(MUX)完成,T1,T2以及Hash表则通过配置FPGA自带的Block RAM IPCore实现. 利用Bit-Extraction算法预先处理原始Key集,根据得到提取的特殊位确定L个MUX的控制位的值,以及预计算得到T1,T2表格中存储的各项数据.第二个位选择操作本质上也是通过MUX实现,假设从T1表中读出的两个bit_index的值分别为I1和I0,且I1>I0,则B0直接用两个MUX就可以得出,而则由以下等式算出:生成offset的电路由简单的位运算操作生成,我们用一个简单的只有3bits数据的mask和B1举例说明,假设mask ={m2,m1,m0},B1= {b2,b1,b0},那么offset的输出{x2,x1,x0}可由以下Boolean等式求出:位选择操作和位运算操作逻辑电路具有运算速度快、硬件消耗资源少的特点,非常适合利用其进行高速硬件Hash表的设计. 但是在Key集的长度较长(L>24bits),而且数据N较大(N≥64K)的情况下进行位选择操作时,出现每一个相同T2地址对应的Hash表存储块内存储Key的数目过多的情况,容易导致Hash冲突,降低Hash 表的负载因子. 我们可以对Hash函数设计进行改进,在第二级位选择操作之后,再增加一个与T1结构一样的查找表和一个与第二级位选择操作一样的位选择操作,将Key的子集进一步分集. 改进后设计有三级位选择操作,虽然会降低硬件电路运行速度,但是能够提高Hash表的利用率和可支持的数据集的大小.3.3 结果分析与对比本设计在Xilinx ISE上用Virtex-6 XC6VSX475T实现,根据Key集的长度L以及LA的值也即T1的大小(2LA)不同分别进行仿真,得到硬件资源消耗的数量和系统时钟频率如表3所示,其中32 bits和48 bits使用三级位选择操作实现.另外,把T1的大小分别设置为1K、2K,将Key集的大小N从120K增加到480K,仿真得到负载因子结果如图2所示. 其中,静态曲线是通过多个固定大小的数据集,预计算得到T1、T2和Hash Table中各项值,算出负载因子. 而动态曲线是通过在一个初始大小的数据集中动态插入新的Key得到的,图2(a)中对应的初始数据集大小为120K,(b)中初始数据集大小为240K. 可以看出,当|T1| = 1K,数据集N小于140K,负载因子将近1,设计的Hash表是近似最小完美Hash表. 随着数据集N的增大,负载因子逐渐降低,在N等于240K左右时,负载因子约为0.7. 动态插入得到的Hash表负载因子往往比静态生成的大. 当|T1| = 2K时,得到类似的结果,但是相同条件下支持的数据集大小是|T1| = 1K时的2倍.本设计支持新Key的不断更新插入,在持续插入过程中,表T1中的数据内容不发生变化. 表T2中的数据mask以及blk_vec将发生变化,而且已经存储在T2表格中的一整条记录,随着新Key的插入需要移动到新的存储位置. 对Key集的大小N从120K到480K分别进行动态插入和静态插入,得到的T2表格中需要移动的最大数据记录个数如图3所示. 当数据集大小为480K时,需要移动的最大数据记录个数为19.最后分析本设计中每个Key的存储空间,假设数据集大小N与T1查找表大小之比为β= N/|T1|,T1表存两个长度为[log2LA]的bit_index,那么T1表所需的存储空间为2N[log2LA]/β. T2表存储的内容包括mask,blk_vec以及base,其中mask的长度为L-log2|T1|-4,blk_vec的长度为8 bits,base的长度为[log2N],所以T2表所需的存储空间为4N(L+log2β+4)/β. 每个Key总的存储空间可以通过(2[log2LA]+4L+4log2β+16)/β计算得出. 考虑到Hash冲突和负载因子,将合理的β取值设为50到100,则平均每个24 bits的Key所需的存储空间为2.8 bits到5.6 bits,与表3中实际测试得到的block RAM的消耗量一致.本文设计并验证了一种适用于硬件实现的近似最小完美Hash函数. 通过对定长Key进行预处理后,设计构建完美Hash函数,利用简单的硬件逻辑电路实现,可以支持满足几百K的大数据量高速表检索要求. 在表4中,我们将该设计与典型的硬件Hash函数进行详细对比,得出该Hash表设计具有电路结构简单、存储资源消耗低、支持动态更新以及可以支持几百K大小的数据集等特点. 该设计可以在需要高速实时表查找的各种场景,包括在新型网络架构NDN(Named Data Networking,命名数据网络)得到应用[17],解决软件实现的Hash函数查找速度无法满足大吞吐量的服务器以及骨干网中数据处理速度要求的问题. 另外对利用SRAM构建CAM电路中的存储单元提供方法参考.【相关文献】1 Dharmapurikar S,Krishnamurthy P,Sproull TS,et al. Deep Packet Inspection Using Parallel Bloom Filters. IEEE Micro,2004,24(1): 52-61.2 杜飞,董治国,苗琳,等.基于无冲突哈希表和多比特树的两级IPv6路由查找算法.计算机应用,2013,33(5):1194-1196.3 Xu Y,Liu ZB,Zhang ZY,et al. High-throughput and memory-efficient multimatch packet classification based on distributed and pipelined hash tables. IEEE/ACM Trans. on Networking,2014,22(3): 982-995.4 Baker ZK,Prasanna VK. A computationally efficient engine for flexible intrusion detection. IEEE Trans. on VLSI Systems,2005,13(10): 1179-1189.5 Alicherry M,Muthuprasanna M,Kumar V. High speed matching for network IDS/IPS. Proc. of the IEEE Int. Conf. on Network Protocols. Washington,DC. IEEE CS Press. 2006. 187-196.6 Sourdis I,Pnevmatikatos D,Wong S,et al. A reconfigurable perfect-hashing scheme for packet inspection. Proc. of the IEEE Int. Conf. on Field Programmable Logic and Applications. Washington,DC. IEEE CS Press. 2005. 644-647.7 Pagh R,Rodler FF. Cuckoo hashing. Journal of Algorithm,2004,51(2): 122-144.8 Ficara D,Giordano S,Kumar S,et al. Divide and discriminate: Algorithm for deterministic and fast hash lookups. Proc. of ACM/IEEE ANCS. Los Alamitos,CA. IEEE CS Press. 2009. 133-142.9 Kumar S,Turner J,Crowley P. Peacock hashing: Deterministic and updatable hashing for high performance networking. Proc. of IEEE INFOCOM. Washington,DC.IEEE CS Press. 2008. 101-105.10 István Z,Alonso G,Blott M,et al. A flexible hash table design for 10Gbps key-valuestores on FPGAs. Proc. of the 23rd Int. Conf. on Field Programmable Logic and Applications (FPL 2013). Washington,DC. IEEE CS Press. 2013. 1-8.11 Bando M,Artan NS,Chao HJ. Flashlook: 100-gbps hash-tuned route lookup architecture. Proc. of the Int. Conf. on High Performance Switching and Routing. Washington,DC. IEEE CS Press. 2009. 1-8.12 Bloom B. Space/time trade-offs in hash coding with allowable errors. Communications of ACM,1970,13(7): 422-426.13 Lu Y,Prabhakar B,Bonomi F. Perfect hashing for network applications. IEEE Symp. on Information Theory. Washington,DC. IEEE CS Press. 2006. 2774-2778.14 Song H,Dharmapurikar S,Turner J,et al. Fast hash table lookup using extended bloom filter: An aid to network processing. ACM SIGCOMM. New York. ACM. 2005. 181-192.15 Bando M,Artan NS,Chao HJ. Highly memory-efficient loglog hash for deep packet inspection. IEEE GLOBECOM. Washington,DC. IEEE CS Press. 2008. 1-6.16 Antichi G,Ficara D,Giordano S,et al. Blooming trees for minimal perfect hashing. IEEE GLOBECOM. Washington,DC. IEEE CS Press. 2008. 1-5.17 张良,刘敬浩,李卓.命名数据网络中基于Hash映射的命名检索.计算机工程,2014,40(4):108-111.。

搜索引擎中的哈希算法

搜索引擎中的哈希算法

搜索引擎中的哈希算法随着互联网的不断发展,搜索引擎成为了我们日常生活中不可或缺的一部分。

无论是查找资料,还是查询商品,搜索引擎都可以帮助我们快速便捷地定位所需信息。

然而,在搜索引擎背后的技术中,哈希算法是一种非常重要的计算机算法,它能够帮助搜索引擎更加高效地处理数据和提供搜索结果。

什么是哈希算法?哈希算法是一种将任意长度的消息变换成固定长度输出(通常较短)的算法。

哈希算法的输出结果我们称之为哈希值,这个值通常用于数据校验、散列函数和消息认证码等方面。

哈希算法具有以下几个特点:1. 输入数据的长度可以是任意的,但是输出的结果长度是固定的。

这样就能够将不同长度的数据进行“压缩”成一样的长度。

2. 哈希算法是一种单向加密,即不能通过哈希值推算出原始数据内容。

3. 对于输入数据的任意改变,都会导致哈希值的改变。

4. 哈希算法的结果分布均匀,尽可能避免了哈希冲突的发生。

哈希算法在搜索引擎中的应用在搜索引擎中,哈希算法主要用于对文档进行索引和快速查找。

在搜索引擎的建立过程中,需要将网页内容存储到索引库中,并对每个网页的关键信息进行提取和处理,生成索引。

由于搜索引擎需要处理的网页数量非常之大,如果每次查找都要全面地遍历所有的网页,那么搜索效率会非常低下。

因此,在处理搜索请求之前,需要先根据搜索关键词计算出哈希值,然后通过哈希值快速地定位到可能含有搜索结果的大约范围。

具体来说,搜索引擎可以将所有文档的关键信息进行哈希值的计算,然后将哈希值作为索引内部的一个标识符。

当有新的搜索请求进来时,可以直接计算搜索关键词的哈希值,然后在哈希表中查找对应的索引,找到可能含有搜索结果的网页范围。

这样,搜索引擎就能够通过哈希算法处理大量的数据,在保证速度的同时,还能够实现快速高效地搜索。

除了在文档索引中的应用外,哈希算法还可以用于判断两个文件是否相同,数据加密等方面。

在实际应用中,不同的哈希算法都有自己的优缺点,需要根据实际情况来选择。

哈希函数的设计原则和优化策略

哈希函数的设计原则和优化策略

哈希函数的设计原则和优化策略哈希函数是计算机科学中常用的一种算法,用于将任意长度的输入数据映射为固定长度的哈希值。

在很多应用中,哈希函数起到了至关重要的作用,例如数据加密、数据验证和数据索引等。

本文将探讨哈希函数的设计原则和优化策略。

一、哈希函数的设计原则1. 低冲突率:哈希函数应该尽量减少冲突的发生,即不同的输入应该产生不同的哈希值,这样可以最大程度地减少数据的碰撞,提高数据的查询速度。

2. 高效计算:哈希函数的计算应该尽可能地高效,即输入数据较小的改动也不应该造成计算复杂度的显著增加,提高处理速度和效率。

3. 均匀分布:哈希函数应该尽可能地将不同的输入数据均匀地映射到哈希值空间中,避免出现过多的热点数据。

4. 确定性:相同的输入应该始终产生相同的哈希值,这样可以实现数据的可持久化和一致性校验。

二、优化策略1. 良好的散列函数选择:选择一个合适的散列函数可以有效地提高哈希函数的性能。

通常,散列函数应该具备高效计算、低碰撞率和均匀分布等特点。

2. 哈希冲突解决策略:即使选择了好的散列函数,冲突仍然会发生。

为了避免冲突对哈希函数性能的影响,可以采用开散列(开放寻址法)和闭散列(链式寻址法)等策略。

- 开散列:当发生哈希冲突时,将冲突的键值对放到散列表中的其他位置。

开散列的方法有线性探测法、平方探测法和双重散列法等。

- 闭散列:当发生哈希冲突时,将冲突的键值对存储在同一个位置,使用链表或者其他数据结构来解决冲突问题。

3. 动态调整哈希表大小:为了提高哈希表的性能,可以根据数据量的变化来动态调整哈希表的大小。

当负载因子超过某个阈值时,可以进行扩容操作,减少哈希冲突的概率,提高查询效率。

4. 优化哈希函数参数:某些哈希函数需要选择一些参数来调节性能。

通过调整这些参数,可以改善哈希函数的散列效果,减少冲突率。

总结:哈希函数的设计原则和优化策略对于提高数据的查询效率和数据的一致性至关重要。

通过选择合适的散列函数、冲突解决策略以及动态调整哈希表大小等方法,可以有效地提高哈希函数的性能和应用的效果。

常用的哈希函数

常用的哈希函数

常用的哈希函数1. 定义哈希函数(Hash Function)是一种将任意大小的数据映射到固定大小值的函数。

它接收输入数据,经过计算后生成一个固定长度的哈希值(也称为散列值或摘要)。

哈希函数具有以下特点:•输入数据可以是任意长度的•输出的哈希值长度固定•相同输入产生相同输出•不同输入产生不同输出•哈希值不能被逆向计算出原始输入2. 用途2.1 数据完整性校验哈希函数可以用于校验数据的完整性,确保数据在传输或存储过程中没有被篡改。

发送方在发送数据之前,通过计算数据的哈希值并将其附加到数据中。

接收方在接收到数据后,重新计算接收到数据的哈希值,并与附加的哈希值进行比较。

如果两个哈希值一致,则说明数据没有被篡改。

2.2 密码存储和验证在用户注册和登录系统时,通常需要对用户密码进行存储和验证。

为了保护用户密码,在存储时可以使用哈希函数对密码进行散列处理,并将散列后的结果存储在数据库中。

当用户登录时,系统会对用户输入的密码进行哈希处理,并与数据库中存储的散列值进行比较,以验证密码的正确性。

2.3 数据唯一标识哈希函数可以将数据映射为唯一的哈希值,用作数据的唯一标识符。

在分布式系统中,可以使用哈希函数将数据分配到不同的节点上,实现负载均衡和高效查询。

2.4 加密和数字签名哈希函数在加密和数字签名领域也有广泛应用。

例如,在数字证书中,哈希函数用于生成证书的签名,以确保证书的完整性和真实性。

在对称加密算法中,哈希函数用于生成消息认证码(MAC)来保证数据完整性。

3. 常见的哈希函数3.1 MD5(Message Digest Algorithm 5)MD5是一种广泛使用的哈希算法,它接收任意长度的输入,并输出128位(16字节)长度的哈希值。

MD5具有以下特点:•高度不可逆:无法通过已知的MD5值反推出原始输入•快速计算:对于给定输入,计算MD5值非常快速•冲突概率较高:由于固定输出长度限制,在大量数据中存在可能产生相同MD5值(冲突)的概率MD5的应用已经逐渐减少,因为其安全性较低。

最小完美哈希函数

最小完美哈希函数

1.哈希函数任意函数h(x)都可以说哈希函数,一般来说,一个良好的哈希函数可以尽量避免重复。

x的集合是参数域,h(x)的集合是值域。

2.完美哈希函数完美哈希函数,就是完全不会冲突的哈希函数,这要求函数的值域至少比参数域要大3.最小完美哈希函数最小完美哈希函数,就是指函数的值域和参数域的大小完全相等,一个也不多4.保序最小完美哈希函数保序的意思就是指这个哈希之后顺序是不变的,同时还能满足其他两个条件。

讨论一个问题,其中要解决用尽量少的空间在尽量少的时间内查找一个集合中的一个元素(可以进行预处理)。

当时我们分析了trie、binary tree、block tree、hashing等各种查询方法的时空复杂度方面的优势劣势。

讨论到最后对时空复杂度的限制都到了苛刻的地步。

为了达到空间复杂度严格为n、每次查询时间复杂度为O(1),我提出针对已知数据集构造一个“特别”的哈希函数,该函数对于当前数据集满足任意两个不同的key通过哈希后不会产生冲突。

哈希是一种常用的具有查找表功能并且提供平均情况下快速访问的标准方法。

哈希函数h:将n个键值xj的集合映射到一个整数集合的函数h(xi),其值域是0<=h(xj)<=m-1,允许重复。

其中m>n/a,a(<=1)是装载因子。

a越小,两个不同键值在相同哈希值相互冲突的可能性越小,然而冲突总是不可避免。

完美哈希函数若一个哈希函数满足对于任意的xi和xj,当且仅当i=j时才有h(xi)=h(xj),就是完美哈希函数(Perfect Hash Function, PHF)。

即对一个键值集合L进行哈希时,不可能产生任何冲突。

如果哈希函数不仅是完美的,并映射到值域范围m=n,n个键值中的任意一个都一一映射到唯一整数,这是装载因子a=1,该函数称为“最小完美哈希函数”(Minimal Perfect Hash Function, MPHF)。

若一个最小完美哈希函数同时满足对于xi<xj,有h(xi)<h(xj),即满足“保序性”(order preserving),则称为保序最小完美哈希函数(Order Preserving Minimal Perfect Hash Function, OPMPHF)。

哈希函数的概念

哈希函数的概念

哈希函数的概念
哈希函数是一种将任意长度的输入(也称为'消息')映射到固定
长度输出(也称为'哈希值'或'数字指纹')的算法。

哈希函数的输出通常是一个固定长度的十六进制字符串。

这个字符串可以用于表示原始数据的数字指纹,以便于在数据存储和比较中进行快速检索。

哈希函数通常用于密码学领域来保证数据的完整性和安全性。

它们可以用于将敏感信息(如密码)转换为不可逆的哈希值,以便在存储和传输期间保护数据的机密性。

此外,哈希函数还可以用于数字签名、身份验证和数据完整性检查等方面,以确保数据没有被篡改或被恶意软件攻击。

哈希函数的设计要求包括:高效性、均匀分布性和抗碰撞性。

高效性指哈希函数需要在短时间内计算出哈希值。

均匀分布性指哈希函数的输出必须在哈希函数定义域内均匀分布。

抗碰撞性指哈希函数应该能够避免相同的输入产生相同的哈希值。

常见的哈希函数包括MD5、SHA-1、SHA-256和SHA-512等。

但是,随着计算机技术的发展,一些哈希函数已经被证明易于攻击,因此需要谨慎选择和使用。

- 1 -。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最小完美哈希函数哈希函数h是一个能够将n个键值x j的集合映射到一个整数集合的函数h(x i),其值域范围是0≤h(x j)≤m-l,允许重复。

哈希是一个具有查找表功能并且提供平均情况下快速访问的标准方法。

例如,当数据包含n个整数键值。

某常用哈希函数采用h(x)=x mod m,其中m 是一个较小的值,且满足m>n/a。

a是装载因子,表示记录数和可用地址数的比例关系。

m一般选择一个素数,因此如果要求提供一个对1000个整数键值进行哈希的函数,一个程序员可能会建议写出如下函数形式:,h(x)=x mod 1399。

并且提供一个装载因子为。

a=0.7的表,该表声明能够存放1399个地址。

a越小,两个不同键值在相同哈希值相互冲突的可能性就越小,然而冲突总是不可避免。

第1次考虑这个问题时,事实可能让人吃惊,最好的例子莫过于著名的生日悖论(birthday paradox)。

假定一年有365天,那么要组合多少个人,才能使得出现生日相同的人这一概率超过0.5呢?换句话说,给定一个365个哈希槽(hashslot)。

随机选择多少个键值才能够使得出现冲突的概率超过0.5?当首次面对这样一个问题时,一般的反应肯定是认为需要很多人才行。

事实上,答案是只需区区23人。

找到一个能够满足现实大小要求且无冲突的哈希函数的几率小到几乎可以忽略25。

例如,一个1000个键值和1399个随机选择的槽,完全没有冲突的概率为 2.35×10-217(概率的计算诱导公式将在下一节中给出,以公式4.1代入m=1399和n=1000得到),如何才能最好地处理这些不可避免冲突?这一话题将在本节中以大段篇幅展开,这里我们正是要找到其中万里挑一的能够避免所有冲突的哈希函数。

25可以试图在一群人中做这样一个有趣的实验,笔者曾在讲述哈希表的课上和同学们做过多次这样的实验。

有一项很重要的事情往往被我们忽略,即参加者必须事先在纸上写下他们的生日(或者其他任意日子)。

然后才能开始核对的工作,这样才能消除神奇的负反馈。

在我们的实验中,除非这样做了,否则也许必须找到366个同学才能遇到第1次碰撞,也许这乜存在心理学悖论吧。

如果在一般的哈希函数中再增加一条额外的性质,即对于任意的x i和x j,当且仅当i=j时才有h(x i)=h(x j),这就是完美哈希函数(perfect hash function)。

这里,当对一个键值集合L进行哈希时,不可能出现任何冲突。

如果哈希函数不仅是完美的,并映射到的值域范围为m=n,n个键值中的任意一个都一一映射到唯一整数(该整数是介于1~n的某个整数),这时表的装载因子是a = 1.0,因此该函数称为“最小完美哈希函数”(minimal perfect hash function),或者简记为“MPHF”。

一个MPHF保证了任何一个键值只需进行一次探测(one-probe)访问,并且表中不包含无用槽。

最后,如果哈希函数还具有这样的性质,即若x i<x j,则有h(x i) <h(x j),这称为“保序性”( order preserving)。

给定一个保序的最小完美哈希函数(简写为“OPMPHF”,读作“oomph!”),那么键值可以在常量时间内找到,而不需要任何空间开销。

并且如果需要的话,还可以按序访问。

一个OPMPHF能够直接且简单地返回一个键值的序号。

当煞,一个MPHF或者OPMPHF对某一个键值集合L有效,但可能对另一个集合就不“完美”了,因此这里不过是对一个单一静态集合预先计算( precalculated)了查找函数。

然而在空间节省很大,并且预先计算被授权的场合下才能这么做。

作为例子,表4-3给出了我们曾经使用过的12个键值的一个OPMPHF。

这个哈希函数的推导过程在下节中将展开讨论。

构造的过程预先假定存在两个一般的哈希函数h1(t)和h2(t),它们都是将字符串映射到范围O~m-1的一个整数。

其中m≥n,并且允许重复。

一种定义方法是用数值来表示基数为36的字符串,与前面提到的一样,最后计算权重之后得到wj,这里t[i]是用基数为36的值描述的术语中第f个字符,|t|表示术语t的长度。

那么不同的权重集合W1[i]和W2[i]中的i为1≤i≤|t|,这样就导出了两个不同的函数h1(t)和h2(t)。

与这两个函数一起,还需要一个特别的数组g。

它需要继续把O...m-1映射到O...n-1,如表4-3 (b)所示。

给某个字符串t,采用OPMPHF h(t)的方法计算公式为:h(t)=g(h1(t))+ n g(h2(t))这里+n表示加法执行后还需对n取模,即先把两个数相加。

然后把这个数除以n,最后取余数(例如4 +n7=2)。

换句话说,首先计算两个非完美哈希函数的值,用映射g分别计算这两个哈希函数的值。

然后将其相加后对n取模,例子字典中的计算结果可以在表4-3 (a)的第4列中找到。

如同变戏法一样,最后的哈希值确实就是字符串列表中的原位置26。

表4-3最小完美哈希函数表(b)哈希函数g的索引术语集进行计算的话,那么就不必存放字符串或者字符串指针。

只需要存储f t值,而术语t的倒排文件地址直接从数组中的第h(t)位置就能找到。

26译者注:可以看出在表4-3 (a)中最后计算的h(t)值从0—11顺序摊列,可知h即保序,又单射且满射,这些性质符合OPMPHF的定义要求。

27译者注:这里其实表达的是通过字符串本身能够建立与其编号对应的关系,假定我们已知单词“bed”的三个字母的编码分别为ABC,其在字典中按序排放的顺序为R,那么函数h(t)的就是从ABC计算出R的公式。

这里有一个难题,描述哈希函数h需要多少存储空间?一个MPHF至少需要1.44n比特的存储空间(Fox及Heath等1992),更典型的很容易计算出对于大数的n,MPHF大约需要每个键值4个—20比特。

而描述OPMPHF所需要的空间还要更大,大约需要至少nlogn比特的存储空间(Fox等1991)。

在OPMPHF中,两个哈希函数h1和h2可以有较小的权重表W1和W2描述,因此它们需要的空间可以忽略不计;另一方面,数组g有m个项,即便是紧凑存放,也需要占用mlogn比特。

下一节将要介绍的方法采用了m= 1.25n的比例关系。

这也是为什么在表4-3的例子中,n(n= 12)个字符串m=15的数组g来处理。

即数组g占用了25比特每字符串,或者,在实际的带有索引项的术语存储为4字节的整数28。

对于假定n=1 000 000个单词的字典,大约需要1.25×4×1 000 000=5 MB的存储开销,另外8MB依然需要存放磁盘指针( disk pointer)和术语词频。

从整体上看,如果OPMPHF被实际使用的话,与3-in-4的前端编码所需的15.5 MB相比,字典能够降佤到大约13 MB。

完美哈希函数的设计在介绍找到最小哈希函数的算法前,首先让我们计算一下生日悖论的概率。

假定n个项将被哈希到m个槽内,第1项可以没有任何碰撞风险的情况下放在某个槽内;第2项的放置能够成功避免冲突的概率为(m-l)/m,因为此时已经有一个槽不可用了;第3项的放置概率是(m-2)/m。

依此类推,连续插入n个项而不发生一次冲突的概率就是这些概率的乘积:(4.1)当m= 365且n=22时,概率为0.524;当n=23时,概率下降到0.493。

因此一个屋子里如果有23个人,那么很有可能有两个人的生日是同一天。

现在我们来看数组g的构造过程,它是表4-3例子中MPHF的奥秘所在。

让我们首先回忆一下如下3组公式:28译者注:数组g为每个术语分配25比特,每个术语存放ft需要8比特。

大约需要32比特,即4字节。

这里t[i]是字符串中第i个要被哈希的字符,构造一个OPMPHF 第1步就是要随机地选择函数h1和h2的映射方法。

有很多办法可以实施,最简便的方法是按照其定义构造随机整数数组W1和W2,一旦构造好,找到这样一个函数g就可以开始了。

将这个问题可视化为一个m点图(m-vertex graph),每个顶点标记上0~m-1的数。

每条边代表一个术语序号,定义为(h1(t)),(h2(t))。

字典中的每个术语对应于图上的一条边,两个哈希值定义了该边连接的哪两个顶点。

最后为每条边用h(t)值标记,这里h(t)就是术语t的哈希函数值。

图4-4中的图对应表4-3 (a)中的哈希函数h1和h2。

这里有m=15个顶点,有n=12条边。

一般的图算法(Graph algorithm)把顶点数定义成n,边数定义为m。

但是在这个讨论中,一致性需要逆着这个传统来讨论29。

图4-4对应表4-3哈希函数的图模型29译者注:这里只是代数方法的不同,定义m为顶点,n为边。

现在我们需要的是计算映射g,使之能够将每个顶点映射到0~n-1的整数。

即对于每条边(h1(t)),(h2(t)),该映射为:g((h1(t))+ng(h2(t)),这个值作为边的标记30。

对于一个一般的图,找到某个标记。

如果存在的话,是很难的。

但是如果图已知是无环的,即不存在一个封闭的由边构成的环(cycle of edges)。

例如,图4-4就是一个无环图,但是如果这里加上一条从2~8的边,那么就形成了2-4-8-2的环,也就不再符合无环的要求了。

对于一个无环图,理想的函数g是很容易推导出的。

任意选择一个未处理的顶点,令g(v)=0。

顺着从该点出发的边,这些边指向的顶点用该边的h值标记下一代的顶点,这时这个值等于边值减去项点值之差(这个顶点也是边的一端)。

如果不存在未标记的顶点,那么就选择下一个根。

周而复始,直到所有的顶点都被做好标记,这时映射函数g宣告完成。

举个例子,假定我们选择图4.4中的顶点0作为一个连通分量(connectedcomponent)的根。

令g[0]=0 31,那么g[3]就必须赋值为732。

这样一来,按照顺序g[6]就必须赋值为l,同时g[1]被赋值为4。

由于g[6]赋值为1,g[10]就必须赋值为2,同理g[12]赋值为0,这样就做完了以顶点0为根的连通分量的赋值工作。

下一个未标记的顶点在本例中为2,将被选做一个新的连通分量的根,即g[2l=0、g[4]=6且g[8l=3。

最后顶点5被当做根,整个余下的顶点都在这次连通分量的赋值过程中分配完毕。

如果图不是无环的,这个标记的过程可能会在一个循环中打圈圈,持续不断地为那些已经处理过的顶点标记不同的标签(这与之前的标签不同)。

这在一个无环图中是不可能的,打标记总是不会出错。

鉴于此,将测试是否有环的工作就必须增加到标记处理过程中。

图4-5描述了处理任意无向图G(V,E)的过程,它假定adjacent(v)为点的邻接点列表。

相关文档
最新文档