`
zhaohaolin
  • 浏览: 1011282 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

暴雪的哈希算法 - [转载]

阅读更多

暴雪公司有个经典的字符串的hash公式 

先提一个简单的问题,假如有一个庞大的字符串数组,然后给你一个单独的字符串,让你从这个数组中查找是否有这个字符串并找到它,你会怎么做? 

有一个方法最简单,老老实实从头查到尾,一个一个比较,直到找到为止,我想只要学过程序设计的人都能把这样一个程序作出来,但要是有程序员把这样的程序交给用户,我只能用无语来评价,或许它真的能工作,但...也只能如此了。 

最合适的算法自然是使用HashTable(哈希表),先介绍介绍其中的基本知识,所谓Hash,一般是一个整数,通过某种算法,可以把一个字符串"压缩" 成一个整数,这个数称为Hash,当然,无论如何,一个32位整数是无法对应回一个字符串的,但在程序中,两个字符串计算出的Hash值相等的可能非常小,下面看看在MPQ中的Hash算法 

unsigned long HashString(char *lpszFileName, unsigned long dwHashType) 
{ 
unsigned char *key = (unsigned char *)lpszFileName; 
unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE; 
int ch; 

while(*key != 0) 
{ 
ch = toupper(*key ); 

seed1 = cryptTable[(dwHashType < < 8) ch] ^ (seed1 seed2); 
seed2 = ch seed1 seed2 (seed2 < < 5) 3; 
} 
return seed1; 
} 
 
Blizzard的这个算法是非常高效的,被称为"One-Way Hash",举个例子,字符串"unitneutralacritter.grp"通过这个算法得到的结果是0xA26067F3。 
是不是把第一个算法改进一下,改成逐个比较字符串的Hash值就可以了呢,答案是,远远不够,要想得到最快的算法,就不能进行逐个的比较,通常是构造一个哈希表(Hash Table)来解决问题,哈希表是一个大数组,这个数组的容量根据程序的要求来定义,例如1024,每一个Hash值通过取模运算 (mod)对应到数组中的一个位置,这样,只要比较这个字符串的哈希值对应的位置又没有被占用,就可以得到最后的结果了,想想这是什么速度?是的,是最快的O(1),现在仔细看看这个算法吧 

int GetHashTablePos(char *lpszString, SOMESTRUCTURE *lpTable, int nTableSize) 
{ 
int nHash = HashString(lpszString), nHashPos = nHash % nTableSize; 

if (lpTable[nHashPos].bExists && !strcmp(lpTable[nHashPos].pString, lpszString)) 
return nHashPos; 
else 
return -1; //Error value 
} 
 

看到此,我想大家都在想一个很严重的问题:"假如两个字符串在哈希表中对应的位置相同怎么办?",究竟一个数组容量是有限的,这种可能性很大。解决该问题的方法很多,我首先想到的就是用"链表",感谢大学里学的数据结构教会了这个百试百灵的法宝,我碰到的很多算法都可以转化成链表来解决,只要在哈希表的每个入口挂一个链表,保存所有对应的字符串就OK了。 

事情到此似乎有了完美的结局,假如是把问题独自交给我解决,此时我可能就要开始定义数据结构然后写代码了。然而Blizzard的程序员使用的方法则是更精妙的方法。基本原理就是:他们在哈希表中不是用一个哈希值而是用三个哈希值来校验字符串。 

中国有句古话"再一再二不能再三再四",看来Blizzard也深得此话的精髓,假如说两个不同的字符串经过一个哈希算法得到的入口点一致有可能,但用三个不同的哈希算法算出的入口点都一致,那几乎可以肯定是不可能的事了,这个几率是1:18889465931478580854784,大概是10的 22.3次方分之一,对一个游戏程序来说足够安全了。 

现在再回到数据结构上,Blizzard使用的哈希表没有使用链表,而采用"顺延"的方式来解决问题,看看这个算法: 
int GetHashTablePos(char *lpszString, MPQHASHTABLE *lpTable, int nTableSize) 
{ 
const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2; 
int nHash = HashString(lpszString, HASH_OFFSET); 
int nHashA = HashString(lpszString, HASH_A); 
int nHashB = HashString(lpszString, HASH_B); 
int nHashStart = nHash % nTableSize, nHashPos = nHashStart; 

while (lpTable[nHashPos].bExists) 
{ 
if (lpTable[nHashPos].nHashA == nHashA && lpTable[nHashPos].nHashB == nHashB) 
return nHashPos; 
else 
nHashPos = (nHashPos 1) % nTableSize; 

if (nHashPos == nHashStart) 
break; 
} 

return -1; //Error value 
} 
 

1. 计算出字符串的三个哈希值(一个用来确定位置,另外两个用来校验) 
2. 察看哈希表中的这个位置 
3. 哈希表中这个位置为空吗?假如为空,则肯定该字符串不存在,返回 
4. 假如存在,则检查其他两个哈希值是否也匹配,假如匹配,则表示找到了该字符串,返回 
5. 移到下一个位置,假如已经越界,则表示没有找到,返回 
6. 看看是不是又回到了原来的位置,假如是,则返回没找到 
7. 回到3 

怎么样,很简单的算法吧,但确实是天才的idea, 其实最优秀的算法往往是简单有效的算法。

分享到:
评论

相关推荐

    暴雪哈希算法全部源码

    ### 暴雪哈希算法源码解析与应用 #### 一、暴雪哈希算法简介 暴雪娱乐(Blizzard Entertainment)是一家知名的电子游戏开发公司,其在游戏开发领域有着丰富的经验和深厚的技术积累。其中,一个被广泛讨论且具有较...

    算法学习:暴雪哈希算法

    ### 暴雪哈希算法详解 #### 一、引言 在计算机科学领域,哈希算法被广泛应用于数据检索、存储以及管理等场景。暴雪哈希算法作为一款高效且经典的哈希算法,在游戏开发及文件管理等领域具有重要的应用价值。本文将...

    blizzard_hash.rar_Blizzard hash_blizzard_哈希算法_暴雪 哈希 算法_暴雪hash

    暴雪哈希算法的核心特点在于使用了三个独立的哈希表来减少冲突的可能性。这种设计提高了哈希表的负载因子,从而使得在高并发环境下,哈希表仍能保持较高的性能。每个哈希表都有自己的哈希函数,这使得数据分布更加...

    最快的排序算法 最快的内容查找算法-----暴雪的Hash算法,排序算法数据结构

    该方法的原理是使用三个不同的哈希算法,生成三个哈希值,然后将其与字符串进行比较,通过这种方法可以几乎肯定地确定字符串的唯一性。 Hash算法在数据结构中的应用非常广泛,例如在数据库中使用 Hash索引来快速...

    暴雪字符串哈希.txt

    dwHashType = 0时计算的哈希值用于确定字符串在哈希表中的位置; dwHashType = 1,dwHashType = 2时计算的哈希值用于验证字符串 返回值:字符串的哈希值 */ unsigned long HashString(char *lpszString, ...

    易语言-暴雪登录js算法

    《易语言-暴雪登录js算法解析》 暴雪娱乐公司是全球知名的游戏开发商和发行商,其旗下的游戏产品如《魔兽世界》、《星际争霸》、《暗黑破坏神》等深受玩家喜爱。为了保障用户账户的安全,暴雪采用了复杂的登录验证...

    暴雪MPQ文件查看器源代码

    3. 哈希算法:理解并实现暴雪的特定哈希算法,如STORM哈希,用于文件名查找。 4. 压缩和解压缩:熟悉常见的压缩算法,如LZ77、LZSS等,以便处理压缩后的文件数据。 5. 异常处理:考虑到文件可能损坏或不完整,源代码...

    打造最快的Hash表

    在给定的文档中,暴雪公司采用了一种特定的哈希算法来计算字符串的哈希值。这个算法基于两个种子值(seed1 和 seed2)和一个加密表(cryptTable)。加密表的生成是一个预处理过程,使用一个循环嵌套结构,通过不断...

    解压MPQ的工具WinMPQ

    文件在MPQ中是以哈希表的形式存储,通过特定的哈希算法快速定位到所需文件,这也是MPQ能实现快速读取的关键。 WinMPQ的功能特性主要包括: 1. **解压与提取**:用户可以使用WinMPQ将MPQ文件中的单个或多个文件提取...

    mpq解压工具

    解压过程中可能会用到多种解压缩算法,如LZSS(一种基于滑动窗口的压缩算法)或其他特定于暴雪游戏的解压缩方法。 暴雪游戏资源分析: 在《暗黑破坏神2》中,MPQ文件存储了角色、怪物、物品、地图等所有游戏元素的...

    Lua 5.0 Reference Manual(Revision 1.0) - PDF

    例如,暴雪娱乐在其知名游戏《魔兽世界》中就广泛使用了Lua脚本来增强游戏功能。 #### 二、语言特性与语法 - **类型系统**: - **基本数据类型**:包括数字、布尔值、字符串等。 - **类型转换**:Lua支持自动类型...

    魔兽3地图文件编辑

    6. **文件哈希值**:MPQ文件使用一种名为SHA-1的哈希算法来验证文件完整性。编辑MPQ时,必须更新文件的哈希值,否则游戏可能无法识别修改后的文件。 7. **地图脚本**:魔兽3地图中的逻辑和交互主要由W3X(.w3x)...

    wow登陆器源码

    了解这一部分的源码,可以学习到如何实现安全的用户认证,例如使用哈希算法和盐值对敏感信息进行保护。 2. **游戏资源更新**:登录器在用户登录前,会检查本地游戏资源的版本,与服务器同步最新的游戏数据。源码中...

    mpq解压工具易语言源码

    MPQ(Magic Packet Queue)是暴雪娱乐公司开发的一种文件打包格式,主要用于其游戏资源的存储,例如《魔兽争霸》和《星际争霸》等。这个压缩包文件“mpq解压工具易语言源码”提供了使用易语言实现的MPQ文件和魔兽...

    hs-deck-gatherer:炉石甲板收集者

    7. **数据结构和算法**:为了高效地组织和查找卡组数据,项目可能会用到各种数据结构(如哈希表、树等)和算法(如排序、搜索等)。 8. **单元测试**:作为良好的编程实践,项目的各个组件可能都经过了单元测试,以...

    Relentless:战网模拟魔兽争霸III客户端

    4. **数据结构与算法**:有效的数据结构(如哈希表、队列、堆)和算法(如图搜索、最短路径算法)用于处理地图信息、单位位置、路径规划等问题,提高游戏的计算效率。 5. **用户界面**:虽然“Relentless”主要是...

Global site tag (gtag.js) - Google Analytics