魔獸雜湊演算法封裝和測試

來源:互聯網
上載者:User

      近期由於需要,研究了魔獸檔案打包管理器的相關演算法,重點對其檔案索引表的產生和尋找進行了研究:採用雜湊表進行,在衝突方面的處理方面,採用線性探測再散列。在添加和尋找過程中進行了三次雜湊,第一個雜湊值用來尋找,後兩個雜湊值用來校正,這樣可以大大減少衝突的幾率。

      這裡對其進行了簡單的封裝,擴充時,僅僅需要對結構體進行擴充即可。更為詳細的說明,參考代碼:【轉載請保留著作權,謝謝】

 

一、類聲明標頭檔

 

/////////////////////////////////////////////////////////////////////////////<br />// Name: HashAlgo.h<br />// Purpose: 使用魔獸Hash演算法,實現索引表的填充和尋找功能。<br />// Author: 陳相禮<br />// Modified by:<br />// Created: 07/30/09<br />// RCS-ID: $Id: treetest.h 43021 2009-07-30 16:36:51Z VZ $<br />// Copyright: (C) Copyright 2009, TSong Corporation, All Rights Reserved.<br />// Licence:<br />/////////////////////////////////////////////////////////////////////////////</p><p>#define MAXFILENAME 255 // 最大檔案名稱長度<br />#define MAXTABLELEN 1024 // 預設雜湊索引表大小</p><p>//////////////////////////////////////////////////////////////////////////<br />// 測試宏定義,正式使用時關閉<br />#define DEBUGTEST 1</p><p>//////////////////////////////////////////////////////////////////////////<br />// 雜湊索引表定義<br />typedef struct<br />{<br /> long nHashA;<br /> long nHashB;<br /> bool bExists;<br /> char test_filename[MAXFILENAME];<br /> // ......<br />} MPQHASHTABLE;</p><p>//////////////////////////////////////////////////////////////////////////<br />// 對雜湊索引表的演算法進行封裝<br />class CHashAlgo<br />{<br />public:</p><p>#if DEBUGTEST<br /> long testid; // 測試之用<br />#endif</p><p> CHashAlgo( const long nTableLength = MAXTABLELEN )// 建立指定大小的雜湊索引表,不帶參數的建構函式建立預設大小的雜湊索引表<br /> {<br /> prepareCryptTable();<br /> m_tablelength = nTableLength;</p><p> m_HashIndexTable = new MPQHASHTABLE[nTableLength];<br /> for ( int i = 0; i < nTableLength; i++ )<br /> {<br /> m_HashIndexTable[i].nHashA = -1;<br /> m_HashIndexTable[i].nHashB = -1;<br /> m_HashIndexTable[i].bExists = false;<br /> m_HashIndexTable[i].test_filename[0] = '/0';<br /> }<br /> }</p><p> void prepareCryptTable(); // 對雜湊索引表預先處理</p><p> unsigned long HashString(char *lpszFileName, unsigned long dwHashType); // 求取雜湊值<br /> long GetHashTablePos( char *lpszString ); // 得到在定長表中的位置<br /> bool SetHashTable( char *lpszString ); // 將字串散列到雜湊表中</p><p> unsigned long GetTableLength(void);<br /> void SetTableLength( const unsigned long nLength );</p><p> ~CHashAlgo()<br /> {<br /> if ( NULL != m_HashIndexTable )<br /> {<br /> delete []m_HashIndexTable;<br /> m_HashIndexTable = NULL;<br /> m_tablelength = 0;<br /> }<br /> }<br />protected:</p><p>private:<br /> unsigned long cryptTable[0x500];<br /> unsigned long m_tablelength; // 雜湊索引表長度<br /> MPQHASHTABLE *m_HashIndexTable;<br />};

 

二、類實現檔案

 

/////////////////////////////////////////////////////////////////////////////<br />// Name: HashAlgo.cpp<br />// Purpose: 使用魔獸Hash演算法,實現索引表的填充和尋找功能。<br />// Author: 陳相禮<br />// Modified by:<br />// Created: 07/30/09<br />// RCS-ID: $Id: treetest.h 43021 2009-07-30 16:36:51Z VZ $<br />// Copyright: (C) Copyright 2009, TSong Corporation, All Rights Reserved.<br />// Licence:<br />/////////////////////////////////////////////////////////////////////////////</p><p>#include "windows.h"<br />#include "HashAlgo.h"</p><p>//////////////////////////////////////////////////////////////////////////<br />// 預先處理<br />void CHashAlgo::prepareCryptTable()<br />{<br /> unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;</p><p> for( index1 = 0; index1 < 0x100; index1++ )<br /> {<br /> for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )<br /> {<br /> unsigned long temp1, temp2;<br /> seed = (seed * 125 + 3) % 0x2AAAAB;<br /> temp1 = (seed & 0xFFFF) << 0x10;<br /> seed = (seed * 125 + 3) % 0x2AAAAB;<br /> temp2 = (seed & 0xFFFF);<br /> cryptTable[index2] = ( temp1 | temp2 );<br /> }<br /> }<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />// 求取雜湊值<br />unsigned long CHashAlgo::HashString(char *lpszFileName, unsigned long dwHashType)<br />{<br /> unsigned char *key = (unsigned char *)lpszFileName;<br /> unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;<br /> int ch;</p><p> while(*key != 0)<br /> {<br /> ch = toupper(*key++);</p><p> seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);<br /> seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;<br /> }<br /> return seed1;<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />// 得到在定長表中的位置<br />long CHashAlgo::GetHashTablePos(char *lpszString)</p><p>{<br /> const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;<br /> unsigned long nHash = HashString(lpszString, HASH_OFFSET);<br /> unsigned long nHashA = HashString(lpszString, HASH_A);<br /> unsigned long nHashB = HashString(lpszString, HASH_B);<br /> unsigned long nHashStart = nHash % m_tablelength,<br /> nHashPos = nHashStart;</p><p> while ( m_HashIndexTable[nHashPos].bExists)<br /> {<br /> if (m_HashIndexTable[nHashPos].nHashA == nHashA && m_HashIndexTable[nHashPos].nHashB == nHashB)<br /> return nHashPos;<br /> else<br /> nHashPos = (nHashPos + 1) % m_tablelength;</p><p> if (nHashPos == nHashStart)<br /> break;<br /> }</p><p> return -1; //沒有找到<br />}<br />//////////////////////////////////////////////////////////////////////////<br />// 通過傳入字串,將相應的表項散列到索引表相應位置中去<br />bool CHashAlgo::SetHashTable( char *lpszString )<br />{<br /> const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;<br /> unsigned long nHash = HashString(lpszString, HASH_OFFSET);<br /> unsigned long nHashA = HashString(lpszString, HASH_A);<br /> unsigned long nHashB = HashString(lpszString, HASH_B);<br /> unsigned long nHashStart = nHash % m_tablelength,<br /> nHashPos = nHashStart;</p><p> while ( m_HashIndexTable[nHashPos].bExists)<br /> {<br /> nHashPos = (nHashPos + 1) % m_tablelength;<br /> if (nHashPos == nHashStart)<br /> {</p><p>#if DEBUGTEST<br /> testid = -1;<br />#endif</p><p> return false;<br /> }<br /> }<br /> m_HashIndexTable[nHashPos].bExists = true;<br /> m_HashIndexTable[nHashPos].nHashA = nHashA;<br /> m_HashIndexTable[nHashPos].nHashB = nHashB;<br /> strcpy( m_HashIndexTable[nHashPos].test_filename, lpszString );</p><p>#if DEBUGTEST<br /> testid = nHashPos;<br />#endif</p><p> return true;<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />// 取得雜湊索引表長<br />unsigned long CHashAlgo::GetTableLength(void)<br />{<br /> return m_tablelength;<br />}</p><p>//////////////////////////////////////////////////////////////////////////<br />// 設定雜湊索引表長<br />void CHashAlgo::SetTableLength( const unsigned long nLength )<br />{<br /> m_tablelength = nLength;<br /> return;<br />}<br />

 

三、測試主檔案

 

/////////////////////////////////////////////////////////////////////////////<br />// Name: DebugMain.cpp<br />// Purpose: 測試Hash演算法封裝的類,完成索引表的填充和尋找功能的測試。<br />// Author: 陳相禮<br />// Modified by:<br />// Created: 07/30/09<br />// RCS-ID: $Id: treetest.h 43021 2009-07-30 16:36:51Z VZ $<br />// Copyright: (C) Copyright 2009, TSong Corporation, All Rights Reserved.<br />// Licence:<br />/////////////////////////////////////////////////////////////////////////////</p><p>//////////////////////////////////////////////////////////////////////////<br />// 測試參數設定宏<br />#define TESTNUM 32</p><p>#include <iostream><br />#include <fstream><br />#include "HashAlgo.h"</p><p>using namespace std;</p><p>//////////////////////////////////////////////////////////////////////////<br />// 測試主函數開始<br />int main( int argc, char **argv )<br />{<br /> CHashAlgo hash_test( TESTNUM );</p><p> cout << "取得初始化散列索引表長為:" << hash_test.GetTableLength() << endl;</p><p> bool is_success = hash_test.SetHashTable( "test" );<br /> if ( is_success )<br /> {<br /> cout << "散列結果一:成功!" << endl;<br /> }<br /> else<br /> {<br /> cout << "散列結果一:失敗!" << endl;<br /> }</p><p> is_success = hash_test.SetHashTable( "測試" );<br /> if ( is_success )<br /> {<br /> cout << "散列結果二:成功!" << endl;<br /> }<br /> else<br /> {<br /> cout << "散列結果二:失敗!" << endl;<br /> }</p><p> long pos = hash_test.GetHashTablePos( "test" );<br /> cout << "尋找測試字串:/"test/" 的散列位置:" << pos << endl;<br /> pos = hash_test.GetHashTablePos( "測試" );<br /> cout << "尋找測試字串:“測試” 的散列位置:" << pos << endl;</p><p> //////////////////////////////////////////////////////////////////////////<br /> // 散列測試<br /> for ( int i = 0; i < TESTNUM; i++ )<br /> {<br /> char buff[32];<br /> sprintf(buff, "abcdefg%d.", i);<br /> is_success = hash_test.SetHashTable(buff);<br /> is_success ? cout << buff << "散列結果:成功!位置:" << hash_test.testid << endl : cout << buff << "散列結果:失敗!" << endl;<br /> }<br /> system( "pause" );<br /> //////////////////////////////////////////////////////////////////////////<br /> // 尋找測試<br /> for ( int i = 0; i < TESTNUM; i++ )<br /> {<br /> char buff[32];<br /> sprintf(buff, "abcdefg%d.", i);<br /> pos = hash_test.GetHashTablePos( buff );<br /> pos != -1 ? cout << "尋找測試字串:"<< buff <<" 的散列位置:" << pos << endl : cout << buff << "存在衝突!" << endl;<br /> }</p><p> system( "pause" );<br /> return 0;<br />}<br />

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.