Hash算法

   近期由于需要,研究了魔兽文件打包管理器的相关算法,重点对其文件索引表的生成和查找进行了研究:采用哈希表进行,在冲突方面的处理方面,采用线性探测再散列。在添加和查找过程中进行了三次哈希,第一个哈希值用来查找,后两个哈希值用来校验,这样可以大大减少冲突的几率。
      这里对其进行了简单的封装,扩展时,仅仅需要对结构体进行扩展即可。更为详细的说明,参考代码:【转载请保留版权,谢谢】

一、类声明头文件

[cpp:nogutter] view plaincopyprint?
  1. /
  1. // Name: HashAlgo.h
  1. // Purpose: 使用魔兽Hash算法,实现索引表的填充和查找功能。
  1. // Author: 陈相礼
  1. // Modified by:
  1. // Created: 07/30/09
  1. // RCS-ID: $Id: treetest.h 43021 2009-07-30 16:36:51Z VZ $
  1. // Copyright: (C) Copyright 2009, TSong Corporation, All Rights Reserved.
  1. // Licence:
  1. /
  1. #define MAXFILENAME 255 // 最大文件名长度
  1. #define MAXTABLELEN 1024 // 默认哈希索引表大小
  1. //
  1. // 测试宏定义,正式使用时关闭
  1. #define DEBUGTEST 1
  1. //
  1. // 哈希索引表定义
  1. typedef struct
  1. {
  1. long nHashA;
  1. long nHashB;
  1. bool bExists;
  1. char test_filename[MAXFILENAME];
  1. // ......
  1. } MPQHASHTABLE;
  1. //
  1. // 对哈希索引表的算法进行封装
  1. class CHashAlgo
  1. {
  1. public:
  1. #if DEBUGTEST
  1. long testid; // 测试之用
  1. #endif
  1. CHashAlgo( const long nTableLength = MAXTABLELEN )// 创建指定大小的哈希索引表,不带参数的构造函数创建默认大小的哈希索引表
  1. {
  1. prepareCryptTable();
  1. m_tablelength = nTableLength;
  1. m_HashIndexTable = new MPQHASHTABLE[nTableLength];
  1. for ( int i = 0; i < nTableLength; i++ )
  1. {
  1. m_HashIndexTable[i].nHashA = -1;
  1. m_HashIndexTable[i].nHashB = -1;
  1. m_HashIndexTable[i].bExists = false;
  1. m_HashIndexTable[i].test_filename[0] = '/0';
  1. }
  1. }
  1. void prepareCryptTable(); // 对哈希索引表预处理
  1. unsigned long HashString(char *lpszFileName, unsigned long dwHashType); // 求取哈希值
  1. long GetHashTablePos( char *lpszString ); // 得到在定长表中的位置
  1. bool SetHashTable( char *lpszString ); // 将字符串散列到哈希表中
  1. unsigned long GetTableLength(void);
  1. void SetTableLength( const unsigned long nLength );
  1. ~CHashAlgo()
  1. {
  1. if ( NULL != m_HashIndexTable )
  1. {
  1. delete []m_HashIndexTable;
  1. m_HashIndexTable = NULL;
  1. m_tablelength = 0;
  1. }
  1. }
  1. protected:
  1. private:
  1. unsigned long cryptTable[0x500];
  1. unsigned long m_tablelength; // 哈希索引表长度
  1. MPQHASHTABLE *m_HashIndexTable;
  1. };

二、类实现文件

[cpp:nogutter] view plaincopyprint?
  1. /
  1. // Name: HashAlgo.cpp
  1. // Purpose: 使用魔兽Hash算法,实现索引表的填充和查找功能。
  1. // Author: 陈相礼
  1. // Modified by:
  1. // Created: 07/30/09
  1. // RCS-ID: $Id: treetest.h 43021 2009-07-30 16:36:51Z VZ $
  1. // Copyright: (C) Copyright 2009, TSong Corporation, All Rights Reserved.
  1. // Licence:
  1. /
  1. #include "windows.h"
  1. #include "HashAlgo.h"
  1. //
  1. // 预处理
  1. void CHashAlgo::prepareCryptTable()
  1. {
  1. unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;
  1. for( index1 = 0; index1 < 0x100; index1++ )
  1. {
  1. for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )
  1. {
  1. unsigned long temp1, temp2;
  1. seed = (seed * 125 + 3) % 0x2AAAAB;
  1. temp1 = (seed & 0xFFFF) << 0x10;
  1. seed = (seed * 125 + 3) % 0x2AAAAB;
  1. temp2 = (seed & 0xFFFF);
  1. cryptTable[index2] = ( temp1 | temp2 );
  1. }
  1. }
  1. }
  1. //
  1. // 求取哈希值
  1. unsigned long CHashAlgo::HashString(char *lpszFileName, unsigned long dwHashType)
  1. {
  1. unsigned char *key = (unsigned char *)lpszFileName;
  1. unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
  1. int ch;
  1. while(*key != 0)
  1. {
  1. ch = toupper(*key++);
  1. seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
  1. seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
  1. }
  1. return seed1;
  1. }
  1. //
  1. // 得到在定长表中的位置
  1. long CHashAlgo::GetHashTablePos(char *lpszString)
  1. {
  1. const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
  1. unsigned long nHash = HashString(lpszString, HASH_OFFSET);
  1. unsigned long nHashA = HashString(lpszString, HASH_A);
  1. unsigned long nHashB = HashString(lpszString, HASH_B);
  1. unsigned long nHashStart = nHash % m_tablelength,
  1. nHashPos = nHashStart;
  1. while ( m_HashIndexTable[nHashPos].bExists)
  1. {
  1. if (m_HashIndexTable[nHashPos].nHashA == nHashA && m_HashIndexTable[nHashPos].nHashB == nHashB)
  1. return nHashPos;
  1. else
  1. nHashPos = (nHashPos + 1) % m_tablelength;
  1. if (nHashPos == nHashStart)
  1. break;
  1. }
  1. return -1; //没有找到
  1. }
  1. //
  1. // 通过传入字符串,将相应的表项散列到索引表相应位置中去
  1. bool CHashAlgo::SetHashTable( char *lpszString )
  1. {
  1. const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
  1. unsigned long nHash = HashString(lpszString, HASH_OFFSET);
  1. unsigned long nHashA = HashString(lpszString, HASH_A);
  1. unsigned long nHashB = HashString(lpszString, HASH_B);
  1. unsigned long nHashStart = nHash % m_tablelength,
  1. nHashPos = nHashStart;
  1. while ( m_HashIndexTable[nHashPos].bExists)
  1. {
  1. nHashPos = (nHashPos + 1) % m_tablelength;
  1. if (nHashPos == nHashStart)
  1. {
  1. #if DEBUGTEST
  1. testid = -1;
  1. #endif
  1. return false;
  1. }
  1. }
  1. m_HashIndexTable[nHashPos].bExists = true;
  1. m_HashIndexTable[nHashPos].nHashA = nHashA;
  1. m_HashIndexTable[nHashPos].nHashB = nHashB;
  1. strcpy( m_HashIndexTable[nHashPos].test_filename, lpszString );
  1. #if DEBUGTEST
  1. testid = nHashPos;
  1. #endif
  1. return true;
  1. }
  1. //
  1. // 取得哈希索引表长
  1. unsigned long CHashAlgo::GetTableLength(void)
  1. {
  1. return m_tablelength;
  1. }
  1. //
  1. // 设置哈希索引表长
  1. void CHashAlgo::SetTableLength( const unsigned long nLength )
  1. {
  1. m_tablelength = nLength;
  1. return;
  1. }

三、测试主文件

[cpp:nogutter] view plaincopyprint?
  1. /
  1. // Name: DebugMain.cpp
  1. // Purpose: 测试Hash算法封装的类,完成索引表的填充和查找功能的测试。
  1. // Author: 陈相礼
  1. // Modified by:
  1. // Created: 07/30/09
  1. // RCS-ID: $Id: treetest.h 43021 2009-07-30 16:36:51Z VZ $
  1. // Copyright: (C) Copyright 2009, TSong Corporation, All Rights Reserved.
  1. // Licence:
  1. /
  1. //
  1. // 测试参数设定宏
  1. #define TESTNUM 32
  1. #include <iostream>
  1. #include <fstream>
  1. #include "HashAlgo.h"
  1. using namespace std;
  1. //
  1. // 测试主函数开始
  1. int main( int argc, char **argv )
  1. {
  1. CHashAlgo hash_test( TESTNUM );
  1. cout << "取得初始化散列索引表长为:" << hash_test.GetTableLength() << endl;
  1. bool is_success = hash_test.SetHashTable( "test" );
  1. if ( is_success )
  1. {
  1. cout << "散列结果一:成功!" << endl;
  1. }
  1. else
  1. {
  1. cout << "散列结果一:失败!" << endl;
  1. }
  1. is_success = hash_test.SetHashTable( "测试" );
  1. if ( is_success )
  1. {
  1. cout << "散列结果二:成功!" << endl;
  1. }
  1. else
  1. {
  1. cout << "散列结果二:失败!" << endl;
  1. }
  1. long pos = hash_test.GetHashTablePos( "test" );
  1. cout << "查找测试字符串:/"test/" 的散列位置:" << pos << endl;
  1. pos = hash_test.GetHashTablePos( "测试" );
  1. cout << "查找测试字符串:“测试” 的散列位置:" << pos << endl;
  1. //
  1. // 散列测试
  1. for ( int i = 0; i < TESTNUM; i++ )
  1. {
  1. char buff[32];
  1. sprintf(buff, "abcdefg%d.", i);
  1. is_success = hash_test.SetHashTable(buff);
  1. is_success ? cout << buff << "散列结果:成功!位置:" << hash_test.testid << endl : cout << buff << "散列结果:失败!" << endl;
  1. }
  1. system( "pause" );
  1. //
  1. // 查找测试
  1. for ( int i = 0; i < TESTNUM; i++ )
  1. {
  1. char buff[32];
  1. sprintf(buff, "abcdefg%d.", i);
  1. pos = hash_test.GetHashTablePos( buff );
  1. pos != -1 ? cout << "查找测试字符串:"<< buff <<" 的散列位置:" << pos << endl : cout << buff << "存在冲突!" << endl;
  1. }
  1. system( "pause" );
  1. return 0;
  1. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值