• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 126,  comments - 73,  trackbacks - 0

            先提一個簡單的問題,如果有一個龐大的字符串數組,然后給你一個單獨的字符串,讓你從這個數組中查找是否有這個字符串并找到它,你會怎么做?

            有一個方法最簡單,老老實實從頭查到尾,一個一個比較,直到找到為止,我想只要學過程序設計的人都能把這樣一個程序作出來,但要是有程序員把這樣的程序交給用戶,我只能用無語來評價,或許它真的能工作,但...也只能如此了。

            最合適的算法自然是使用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, 其實最優秀的算法往往是簡單有效的算法。

            http://blog.blogchina.com/article_85296.361466.html

            posted on 2007-08-21 11:51 我風 閱讀(6961) 評論(8)  編輯 收藏 引用

            FeedBack:
            # re: 打造最快的Hash表(轉)
            2007-11-03 01:07 | wo
            不是很懂,"從這個數組中查找是否有這個字符串并找到它",和這怎么聯系上的?謝謝  回復  更多評論
              
            # re: 打造最快的Hash表(轉)
            2007-12-05 17:07 | 祁祁
            果然精妙  回復  更多評論
              
            # re: 打造最快的Hash表(轉)
            2009-03-25 17:03 | akore
            無聊, 跟在字符串數組中找到目標字符串有個屁聯系!  回復  更多評論
              
            # re: 打造最快的Hash表(轉)
            2009-04-21 14:41 | brightcoder
            跟你提的問題有什么關聯  回復  更多評論
              
            # re: 打造最快的Hash表(轉)[未登錄]
            2009-05-22 00:41 | joe
            @akore
            對你相當無語..先看懂再說吧  回復  更多評論
              
            # re: 打造最快的Hash表(轉)
            2009-09-01 13:59 | charrie
            頂,最后三個哈希值的還沒有太明白,前面的正是我需要的,謝謝樓主!  回復  更多評論
              
            # re: 打造最快的Hash表(轉)
            2009-10-12 16:32 | river
            如果只進行一次這樣的查找操作,那么順序查找,當然是唯一選擇;
            你說的高效,是針對要進行無數次這樣在同一個長串中查找子串的操作的情況,對吧?道理是很簡單,確實還不錯。
            你這個文章,意思沒有表達的很清楚,怨不得別人提出質疑;
            同時,題目為“打造最快的hash表”,我不太認同。  回復  更多評論
              
            # re: 打造最快的Hash表(轉)
            2009-10-13 23:17 | Veiir
            @river
            Hash表的目的是讓搜索時間穩定在一個數字上。

            比如有幾百個模型包,要依靠名稱取其中一個,那么如果你逐個比較文件名篩選,如果是這個文件名是a開頭還好,萬一是z開頭呢?會不會花費的時間很長?那么你這個游戲畫面的載入時間豈不是很不穩定?

            如果把這些模型包通過文件名hash運算得出來一個數字,比如20,放到同一個數組array的這個數字的位置array[20],那么以后要讀取這個模型包,僅用知道文件名,通過hash運算得出同樣的數字20,那么你可以直接去取數組array的這個數字位置就好了array[20]。那么你只用了一個hash運算,這個運算所花費的時間是一定的,要比不知道做多少次文件名比較花的時間短多了,取址當然是很快的,那么你游戲畫面載入時間就不會很長,也比較穩定.  回復  更多評論
              
            <2010年8月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            2930311234

            常用鏈接

            留言簿(12)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            C++

            MyFavorite

            搜索

            •  

            積分與排名

            • 積分 - 327097
            • 排名 - 75

            最新評論

            閱讀排行榜

            評論排行榜

            免费久久人人爽人人爽av| 久久免费美女视频| 国产精品久久久久蜜芽| 久久精品免费一区二区| 婷婷五月深深久久精品| 热久久国产精品| 国色天香久久久久久久小说| 久久99热精品| 久久亚洲sm情趣捆绑调教| 亚洲国产精品一区二区久久| 性高朝久久久久久久久久| 99久久精品费精品国产一区二区| 韩国三级中文字幕hd久久精品| 囯产精品久久久久久久久蜜桃| 国内精品久久国产大陆| 伊人色综合久久天天人手人婷| 国产精品99久久久久久www| 国产A级毛片久久久精品毛片| 很黄很污的网站久久mimi色| 欧美亚洲色综久久精品国产| 亚洲国产成人久久一区久久| 国产成人综合久久精品尤物| 色欲久久久天天天综合网精品| 亚洲精品国精品久久99热| 国内精品久久久久久久久电影网| 久久久久99精品成人片试看 | 少妇人妻综合久久中文字幕| 91久久成人免费| 久久精品视频免费| 国产成人久久精品一区二区三区| 亚洲国产日韩综合久久精品| 久久久久国产精品麻豆AR影院| 国产免费久久精品丫丫| 国产精品久久久久天天影视| 国产成人综合久久综合| 久久精品9988| 99久久婷婷国产综合精品草原| 99精品伊人久久久大香线蕉| 精品久久久久久国产免费了| 久久本道综合久久伊人| 欧美久久亚洲精品|