神奇的暴雪哈希算法

暴雪魔兽世界、星际争霸的游玩如独一十分大的MPQ文献,左右文献存储器了游玩正中鹄的最大的知识。,想找出这些词,最复杂的方式是从块长开端。,串联在过来的读书,匹敌各,直到找到相配的灵。暴雪逸才和牛人一定不克如此的做。,他们运用了更智能的方式。 运用一种算法,将字母串紧缩为概数,即hash。继,依据左右概数值,在完整地文献得其次名获取左右字母串,为了直线部分读书。

 

暴雪算法是十分无效的。,同样的来回 Hash”。同样的单向 Hash,它缺点从散列值的逆举动复杂开始日。对基音的创造,inside MPQ其次章有特色的引见,其次章的中文翻译:

贯串计算器语系发作,变得越来越大提高都是处理少量的成绩的方式。,在这一节中,让笔者看一眼MPQ 版式互插成绩和处理方案;

成绩一:您有大方的的字母串。,同时,你有另独一字母串。,必要认识字母串 在已在的字母串块。可以匹敌块正中鹄的每个字母串。,但在实践工程中,你会被发现的人它当作其中的一部分特别的消耗来说太慢了。。得追求此外道路。。因而,你怎地认识左右字母串中在独一缺勤遍历匹敌装饰

处理方案:肉丁土豆泥。肉丁土豆泥是表现更大知识类型的较小知识类型。。在这种情况下, 你可以把肉丁土豆泥存储器在字母串块中,继,您可以计算字母串的反复推敲。,继与已存储器的字母串的反复推敲停止匹敌。。免得有婚配散列值,可以措辞母串匹敌 婚配认可。这种方式称为标定指数。,依据块的规模和字母串的分摊时间的长短,它。

unsignedlongHashString(char*lpszString)

{  

    unsignedlongulHash=0xf1e2d3c4;        

    while(*lpszString!=0)    

    {        

        ulHash<<=1;      

        ulHash+=*lpszString++;      

    }  

    returnulHash;

}

上面编码正中鹄的重大聚会演示了一种十分复杂的散列算法。左右重大聚会在遍历字母串的列队行进中。,将散列值向左卖。,继添加角色值;经过该算法,字母串”” 反复推敲是0x5a858026,字母串”” 反复推敲是0x694cd020;如今,东窗事发的,这是独一全然的复杂算法,缺勤什么实践意义。,由于它在较低的知识范围内发作绝对可预测的出口。,能够会有很多抵触(变化多的的字母串发作相通的反复推敲。。

MPQ体式,运用了独一十分复杂的散列算法(如次所示),创造完整不行预测的反复推敲。,左右算法十分无效。,这执意同样的的单向散列算法。。用散列值来决定惟一的的输出值差不多是不行能的。。运用此算法,文献名 “” 反复推敲是0xf4e6c69d,”” 的反复推敲是 0xA26067F3。

unsignedlongHashString(char*lpszFileName,unsignedlongdwHashType)

{  

    unsignedchar*key=(unsignedchar*)lpszFileName;  

    unsignedlongseed1=0x7FED7FED,seed2=0xEEEEEEEE;  

    intch;

    while(*key!=0)      

    {      

        ch=向上的(*key++);  

        seed1=cryptTable[(dwHashType<<8)+ch]^(seed1+seed2);      

        seed2=ch+seed1+seed2+(seed2<<5)+3;      

    }  

    returnseed1;  

}

成绩二:您尝试在前独一示例中运用相通的标定指数。,你的顺序得断球。,并且不敷快 。免得你想开始,你所能做的执意让顺序不查询AR正中鹄的占有散列值。。或许 您可以停止相似物,看一眼列表中无论有独一字母串。。打电话给正确的,真的?这是不行能的。

处理:肉丁土豆泥是运措辞母串的散列值作为s的块的一类。。我的意义是,肉丁土豆泥运用合格的时间的长短的字母串块(如1024)。,2甚至电源)用于存储器;当您想反省此字母串无论相信肉丁土豆泥中时,为了在肉丁土豆泥中获取该字母串的得其次名,率先计算字母串的反复推敲。,继肉丁土豆泥的时间的长短。从此处,免得您运用与前一节类比的复杂哈希算法,字母串”” 反复推敲是0x5a858026,偏移量0x26(0x5A858026 不计0x16a160 0x400值得的,模0x400值得的0x26)。从此处,左右得其次名的字母串将与新相容的字母串停止匹敌。免得0x26字母串不婚配或不在,这断定块中不在新的字母串。。上面是独一示意图编码:

intGetHashTablePos(char*lpszString,SOMESTRUCTURE *lpTable,intnTableSize)

{  

    intnHash=HashString(lpszString),nHashPos=nHash%nTableSize;      

    if(lpTable[nHashPos].bExists&&!strcmp(lpTable[nHashPos].pString,lpszString))      

        returnnHashPos;  

    else        

        return1;//Error value  

}

上面的描绘有独一骗子的缺陷。。当有抵触(两个变化多的的字母串有相通的反复推敲)发作的时辰怎地办?不言而喻的,它们在肉丁土豆泥中不利用相通的得其次名。。通常的处理方案是为每个散列值导演独一链表。,用于存储器占有哈希抵触的值;

MPQS采取肉丁土豆泥存储器文献的命名以轨道内,虽然表格的体式与通常的方式相当多的变化多的。,率先相异的通常的做法运用反复推敲作为偏移量,存储器实践文献名。MPQs 占有文献名都不存储器。,相反,运用三个变化多的的反复推敲。:肉丁土豆泥偏移量,这两个被用作检验。。这两个选正中鹄的反复推敲用于交换文献名。。自然,在推测上有两种变化多的的文献名来流行相通的三,虽然发送这种情况的能够性是:1:18889465931478580854784,得十足中卫。。

另独一分别的MPQ的肉丁土豆泥的创造,相当作引渡做法(为每个杂种运用链表),当抵触发作时,遍历链表以停止匹敌),请看上面的演示编码,方位独一文献在MPQ读书:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

intGetHashTablePos(char*lpszString,MPQHASHTABLE *lpTable,intnTableSize)

{  

    constintHASH_OFFSET=0,HASH_A=1,HASH_B=2;    

    intnHash=HashString(lpszString,HASH_OFFSET),nHashA=HashString(lpszString,HASH_A),nHashB=HashString(lpszString,HASH_B),nHashStart=nHash%nTableSize,nHashPos=nHashStart;

    while(lpTable[nHashPos].bExists)

    {

        if(lpTable[nHashPos].nHashA==nHashA&&lpTable[nHashPos].nHashB==nHashB)

            returnnHashPos;

        else

            nHashPos=(nHashPos+1)%nTableSize;

            if(nHashPos==nHashStart)

                break;

    }

    return1;//Error value

}

不论编码显现有多复杂,臀部的推测一点也不财政困难。。读取文献时,全然上依照以下列队行进:
1. 计算字母串的三个散列值(用于决定t)。,此外两个是用来反省的。
2. 反省肉丁土豆泥正中鹄的左右得其次名。
3. 左右得其次名在肉丁土豆泥中是空的吗?免得是空的,一定字母串不在。,赢利
4. 免得在,反省此外两个散列值无论婚配。,免得婚配,它指明已找到字母串。,赢利
5. 移到下独一得其次名,免得它曾经谈判达成边线,它预示它还缺勤被被发现的人。,赢利
6. 看一眼它无论回到怪人的得其次名。,免得是,继未发现补偿。
7. 回到3

免得你坚持到底它,您能够曾经坚持到底到了笔者的解说和示例编码。,的MPQ肉丁土豆泥曾经把占非常文献进入MPQ;因而当肉丁土豆泥的每一都被填鸭式学的时,会发作是什么?答案能够会让你不胜骇异。:不克不及添加究竟哪一个文献。某些人能够会问我为什么对文献的定量有如此的的限度局限。,有缺勤办法忽视左右限度局限?,免得你不建立MPQ 的项,甚至不克不及整齐肉丁土豆泥的规模。。这是由于肉丁土豆泥中每个项的得其次名由TH更改。,笔者未发现新的作包工,由于这些得其次名值是文献名的反复推敲。,笔者全然不认识文献的名字是什么。。

授予作者判给

码字母是十分财政困难的。,转载请表明

标点符

神奇的暴雪散列算法

发表评论

电子邮件地址不会被公开。 必填项已用*标注