扩展封装暴雪哈希算法(blizard hash algorithm),并与STL map进行操作性能上的比较

问题描述:

1.blizard hash algorithm 是众所周知的算法,关于它极小的碰撞概率和实现的简洁性一直为热爱技术的朋友津津乐道;

2.blizard hash algorithm 有个致命的问题就是它的实现受制于一个固定的(预先开辟的buffer)的限制,暴雪给出的是1024,也即当hash table 的填充的元素(key value pair)查过1024时,就没办法再往里面进行key value 对填充,这极大的限制了它的使用。在实现的应用,我们经常会向hash table里百万,千万插入key, value对,所以有必要尝试改造扩展它的算法,使得其能动态扩展,以适用我们实现编程中的使用场景;

3.本文以Rehash方式为扩展策略对hash table按素数长度进行扩展;

4.本文使用c++语言重新封装这个算法,并和STL map进行了操作性能上的比较。执行相同的操作,结果是blizard hash所消耗时间为map的五分之一;

程序代码:

#ifndef _BLIZARD_HASH_H_
#define _BLIZARD_HASH_H_

#include <stdlib.h>
#include <stdio.h>
#include <map>

#include "windows.h"

static const int HashSize[] = {17, 37, 79, 163, 331,
673,           1361,        2729,       5471,         10949,
21911,          43853,      87719,      175447,      350899,
701819,         1403641,    2807303,     5614657,     11229331,
22458671,       44917381,    89834777,    179669557,   359339171,
718678369,      1437356741,  2147483647 };

/*
*
*
*
*/
template<class T>
class BlizardHash
{
public:
	static int const INIT_HASH_SIZE = 8;

	typedef struct tagHashNode
	{
		unsigned int hashFirst;
		unsigned int hashSecond;
		char*        key;
		T            value;

		tagHashNode():hashFirst(0), hashSecond(0),
			          key(0), value()
		{

		}

		tagHashNode( const char* _key, const T& _value ): hashFirst(0),
			        hashSecond(0),  value(_value)
		{
			SetKey( _key );
		}

		tagHashNode( unsigned int hash1, unsigned int hash2,const char* _key, const T& _value ):
		    hashFirst(hash1),
			hashSecond(hash2),
			value(_value)
		{
			SetKey( _key );
		}

	    void SetKey( const char* _key )
		{
			size_t len = strlen(_key) + 1;
			key = new char[len];
			strncpy( key, _key, len - 1);
			key[len - 1] = ‘\0‘;
		}

		~tagHashNode()
		{
			delete [] key;
			key = 0;
		}

	}HashNode, *pHashNode;

	/*
	*
	*
	*/
	BlizardHash():m_cryptTable(), m_curSize(INIT_HASH_SIZE),
		          m_tableSize(0), m_tableUsed(0),
				  m_hashTable(0)
	{
		Init();
	}

	/*
	*
	*
	*/
	~BlizardHash()
	{
		Clear();
	}

	/*
	*
	*
	*/
	void Clear()
	{
		Clear( m_hashTable, m_tableSize );

		m_tableSize = 0;
		m_tableUsed = 0;
	}

	/*
	*
	*
	*/
	void Insert( const char* key, const T& value )
	{
		Rehash();

		unsigned int pos = GetHashTablePos( key );
		if( -1 == pos )
		{
			if( Insert( m_hashTable, m_tableSize, key, value ) )
			{
				m_tableUsed++;
			}
		}
	}

	/*
	*
	*
	*/
	T* Find( const char* key )
	{
		unsigned int pos = GetHashTablePos( key );
		if( pos != -1 )
		{
			if( KeyCompare( key, m_hashTable[pos]->key ) )
				return &m_hashTable[pos]->value;
		}

		return NULL;
	}

	/*
	*
	*
	*/
	void Delete( const char* key )
	{
		unsigned int pos = GetHashTablePos( key );
		if( pos != -1 )
		{
			if( KeyCompare( key, m_hashTable[pos]->key ) )
			{
				delete m_hashTable[pos];
				m_hashTable[pos] = 0;
				m_tableUsed--;
			}
		}
	}

protected:

	void Clear( pHashNode* hashTable, unsigned int size )
	{
		for( unsigned int i = 0; i < size; i++ )
		{
			if( hashTable[i] )
			{
				delete hashTable[i];
				hashTable[i] = 0;
			}
		}

		delete [] hashTable;
		hashTable = 0;
	}

	/*
	*
	*
	*/
	bool KeyCompare( const char* keyFirst, const char* keySecond )
	{
		size_t len1 = strlen(keyFirst);
		size_t len2 = strlen(keySecond);
		return len1 == len2 && !strcmp( keyFirst, keySecond );
	}

	/*
	*
	*
	*/
	unsigned long HashFunctor( const char* inputStr, int hashType )
	{
		unsigned char *key = (unsigned char *)inputStr;
		unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;

		int ch;
		while(*key != 0)
		{
			ch = toupper(*key++);
			seed1 = m_cryptTable[(hashType << 8) + ch] ^ (seed1 + seed2);
			seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
		}

		return seed1;
	}

	/*
	*
	*
	*/
	void PrepareCryptTable()
	{
		unsigned long seed = 0x00100001, index1 = 0, index2 = 0;
		unsigned long i = 0;
		for( index1 = 0; index1 < 0x100; index1++ )
		{
			for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )
			{

				unsigned long temp1, temp2;
				seed = (seed * 125 + 3) % 0x2AAAAB;
				temp1 = (seed & 0xFFFF) << 0x10;
				seed = (seed * 125 + 3) % 0x2AAAAB;
				temp2 = (seed & 0xFFFF);

				m_cryptTable[index2] = ( temp1 | temp2 );
			}

		}
	}

	/*
	*
	*
	*/
	unsigned int GetHashTablePos( const char *inputStr )
	{
		const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
		unsigned long nHash = HashFunctor(inputStr, HASH_OFFSET);
		unsigned long nHashA = HashFunctor(inputStr, HASH_A);
		unsigned long nHashB = HashFunctor(inputStr, HASH_B);

		unsigned long nHashStart = nHash % m_tableSize,
		nHashPos = nHashStart;

		while( m_hashTable[nHashPos] )
		{
			if( m_hashTable[nHashPos]->hashFirst == nHashA && m_hashTable[nHashPos]->hashSecond == nHashB )
			{
				return nHashPos;
			}
			else
			{
				nHashPos = (nHashPos + 1) % m_tableSize;
			}		

			if( nHashPos == nHashStart )
				break;

		}

		return -1;
	}

	/*
	*
	*
	*/
	void Rehash()
	{
		if( m_tableUsed >= m_tableSize )
		{
			size_t allSize = sizeof(HashSize)/sizeof( HashSize[0] );
			if( m_curSize < allSize - 1 )
			{
				m_curSize++;
				pHashNode* newTable = new pHashNode[HashSize[m_curSize]];
				memset( newTable, 0x00, sizeof(pHashNode) * HashSize[m_curSize] );
				for( int i = 0; i < m_tableSize; i++ )
				{
					Insert( newTable, HashSize[m_curSize], m_hashTable[i]->key, m_hashTable[i]->value );
				}

				Clear( m_hashTable, m_tableSize );

				m_hashTable = newTable;
				m_tableSize = HashSize[m_curSize];
			}
		}

	}

	/*
	*
	*
	*/
	bool Insert( pHashNode* hashTable, unsigned int tableSize, const char* key, const T& value )
	{
		const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;

		unsigned long nHash = HashFunctor(key, HASH_OFFSET);
		unsigned long nHashA = HashFunctor(key, HASH_A);
		unsigned long nHashB = HashFunctor(key, HASH_B);
		unsigned long nHashStart = nHash % tableSize, nHashPos = nHashStart;

		while( hashTable[nHashPos] )
		{
			nHashPos = (nHashPos + 1) % tableSize;
			if( nHashPos == nHashStart )
			{
				unsigned long pos = nHash % tableSize;
				pHashNode node = new HashNode( nHashA, nHashB, key, value );
				assert( node );
				hashTable[pos] = node;

				return true;
			}

		}

		if( !hashTable[nHashPos] )
		{
			pHashNode node = new HashNode( nHashA, nHashB, key, value );
			assert( node );
			hashTable[nHashPos] = node;

			return true;
		}

		return false;
	}

	/*
	*
	*
	*/
	void Init()
	{
		PrepareCryptTable();

		size_t allSize = sizeof(HashSize)/sizeof( HashSize[0] );
		if( m_curSize < allSize - 1 )
		{
			m_tableSize = HashSize[m_curSize];
			m_hashTable = new pHashNode[m_tableSize];
			memset( m_hashTable, 0x00, sizeof(pHashNode)*m_tableSize );

		}
		else
		{
			m_curSize = INIT_HASH_SIZE;
			m_tableSize = HashSize[m_curSize];
			m_hashTable = new pHashNode[m_tableSize];
			memset( m_hashTable, 0x00, sizeof(pHashNode)*m_tableSize );

		}

	}

private:

	unsigned long m_cryptTable[0x500];

	size_t         m_curSize;

	unsigned long  m_tableSize;   

	unsigned long  m_tableUsed;

	pHashNode*     m_hashTable;

};

/*
* Test hash table
*
*/
void TestBlizardHashTable()
{
	unsigned long start = GetTickCount();

	BlizardHash<int> hashTable;
	const int Len = 500000;
	for( int i = 0; i < Len; i++ )
	{
		char key[16] = {0};
		sprintf(key, "%s_%d", "china", i );

		hashTable.Insert( key, i );
	}

	for( int i = 0; i < Len; i++ )
	{
		char key[16] = {0};
		sprintf(key, "%s_%d", "china", i );

		if( i > 0 && !(i % 50) )
		{
			hashTable.Delete( key );
			assert( !hashTable.Find( key ) );
		}
		else
		{
			assert(i == *hashTable.Find( key));
		}

	}

	unsigned long interval = GetTickCount() - start;
	printf(" hash table consume time is %d \n", interval );
}

/*
* Test STL map
*
*/
void TestBlizardSTLMap()
{
	unsigned long start = GetTickCount();

	std::map<std::string, int > strMap;
	const int Len = 500000;
	for( int i = 0; i < Len; i++ )
	{
		char key[16] = {0};
		sprintf(key, "%s_%d", "china", i );
		std::string keyStr(key);

		strMap.insert( std::make_pair(keyStr, i )) ;
	}

	std::map<std::string, int >::iterator iter = strMap.begin();
	for( int i = 0; i < Len; i++ )
	{
		char key[16] = {0};
		sprintf(key, "%s_%d", "china", i );
		std::string keyStr(key);

		if( i > 0 && !(i % 50) )
		{
			strMap.erase( key );
			assert( strMap.find( key ) == strMap.end() );
		}
		else
		{
			iter = strMap.find( keyStr );
			assert( iter->second == i );
		}

	}

	unsigned long interval = GetTickCount() - start;
	printf(" STL map consume time is %d \n", interval );
}

/*
* Test suite and compare performance
*
*/
void TestSuiteBlizardHash()
{
	TestBlizardHashTable();
	TestBlizardSTLMap();

}

#endif 

compile and run in visual studio 2005

扩展封装暴雪哈希算法(blizard hash algorithm),并与STL map进行操作性能上的比较,布布扣,bubuko.com

时间: 2024-10-06 20:38:51

扩展封装暴雪哈希算法(blizard hash algorithm),并与STL map进行操作性能上的比较的相关文章

用c++封装一个Hash Table,并与STL map 进行操作性能上的比较

问题描述: 1.在计算机科学中,hash table 是一种常用的数据结构,它本质上是一种关联容器,它映射一个key 到value.它通过一个hash function把key映射成一个整数值,这个整数值对应存放value值的容器的下标. 2.它主要支持三种操作:插入key,value对(insert),查询(search)给定key, 删除key, value对(delete); 3.它三种操作的平均时间复杂度为O(1),最糟糕情况下的时间复杂度为O(n): 4.hash table要处理核心

感知哈希算法的java实现

一.原理讲解      实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张图片的指纹越相似, 说明两张图片就越相似. 但关键是如何根据图片计算出"指纹"呢? 下面用最简单的步骤来说明一下原理:            <1>.第一步 缩小图片尺寸      将图片缩小到8x8的尺寸, 总共64个像素. 这一步的作用是去除各种图片尺寸和图片比例的差异, 只保留结构

感知哈希算法&mdash;&mdash;找出相似的图片

Google 图片搜索功能         在谷歌图片搜索中, 用户可以上传一张图片, 谷歌显示因特网中与此图片相同或者相似的图片.         比如我上传一张照片试试效果: 原理讲解         参考Neal Krawetz博士的这篇文章, 实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张图片的指纹越相似, 说明两张图片就越相似. 但关键是如何根据图片计算出"指纹&qu

感知哈希算法(找出相似的图片)

原理讲解 实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张图片的指纹越相似, 说明两张图片就越相似. 但关键是如何根据图片计算出"指纹"呢? 下面用最简单的步骤来说明一下原理: 第一步 缩小图片尺寸 将图片缩小到8x8的尺寸, 总共64个像素. 这一步的作用是去除各种图片尺寸和图片比例的差异, 只保留结构.明暗等基本信息. 第二步 转为灰度图片 将缩小后的图片, 转为6

一致性哈希算法的应用及实现

一致性哈希算法(Consistent Hashing Algorithm)是一种分布式算法,由MIT的Karger及其合作者提出,现在这一思想已经扩展到其它领域.1997年发表的学术论文中介绍了“一致性哈希”如何应用于用户易变的分布式Web服务中.一致性哈希可用于实现健壮缓存来减少大型Web应用中系统部分失效带来的负面影响.(维基百科) >>hash算法的单调性 Hash 算法的一个衡量指标是单调性( Monotonicity ),定义如下:单调性是指如果已经有一些内容通过哈希分派到了相应的缓

一致性哈希算法

tencent2012笔试题附加题    问题描述: 例如手机朋友网有n个服务器,为了方便用户的访问会在服务器上缓存数据,因此用户每次访问的时候最好能保持同一台服务器.已有的做法是根据ServerIPIndex[QQNUM%n]得到请求的服务器,这种方法很方便将用户分到不同的服务器上去.但是如果一台服务器死掉了,那么n就变为了n-1,那么ServerIPIndex[QQNUM%n]与ServerIPIndex[QQNUM%(n-1)]基本上都不一样了,所以大多数用户的请求都会转到其他服务器,这样

[CareerCup] 13.2 Compare Hash Table and STL Map 比较哈希表和Map

13.2 Compare and contrast a hash table and an STL map. How is a hash table implemented? If the number of inputs is small, which data structure options can be used instead of a hash table? 这道题让我们比较哈希表和STL中的map数据结构,在遇到这道题之前,我一直以为map就是c++中的哈希表呢,原来是不同的啊-

算法学习 - Hash Table操作,分离链接法解决哈希冲突

分离链接法 hash table是映射机制的,最大的优点就是它的操作是O(1)级别的.但是会出现哈希冲突,这就需要几种办法来解决.这里先说一种:分离链接法. 就是当插入的位置已经存在一个值之后,那么在这个值之后插入,就可以了,也叫拉链法.(但是其实会降低查找速度,变成O(n)级别) 下面是代码: // // main.cpp // HashTable_SeparateChaining // // Created by Alps on 14-8-5. // Copyright (c) 2014年

SHA1 安全哈希算法(Secure Hash Algorithm)

安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA).对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要.当接收到消息的时候,这个消息摘要可以用来验证数据的完整性.在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要. SHA1有如下特性:不可以从消息摘要中复原信息:两个不同的消息不