HASH的问题,有谁用过HASH算法吗
我现在做一个HASH方面的东西。入口是200W条字符串,每个串的长度为3-8个字符。
我用了很HASH算法,每次的冲突(包括一次,二次,三次....)都达到40%左右,请问有什么好的办法?
[解决办法]
试问你的hash table 开了多大的???
[解决办法]
给出hash函数,冲突多说明hash函数设计不合理
[解决办法]
应该是hash算法的问题,造成了分布不均,所以产生了冲突。
改进一下应该就可以了!
[解决办法]
是你的hash算法设计不够优
可以考虑bitmap结构试试
[解决办法]
用bitmap能解决问题
[解决办法]
不明白你的hash算法是如何设计的,提取特征是如何做的,还有你的这200w条字符串分布是不是均匀(不要都差不多的字符串);
我觉得如果去前4-5字符做为特征,(hash table 以hash算法的最大值)进行hash运算的话,冲突不应该会有这么高。
[解决办法]
强烈的推荐你使用暴雪的mpq技术
我在个人机器上实现过4000万条字符串存储,碰撞很小
需要代码的话,请留下你的邮箱
[解决办法]
这里留下我以前用过的一个小程序,稍做修给后应该可以满足你的要求
#include <iostream>
using namespace std;
#define nTableSize 40000000
#define nMaxStrLen 20
unsigned long cryptTable[0x1000];
typedef struct _MPQHASHTABLE
{
char bExists;
}MPQHASHTABLE;
MPQHASHTABLE HashTable[nTableSize];
int HashATable[nTableSize];
int HashBTable[nTableSize];
char data[nTableSize][nMaxStrLen];
class CHashForMpq
{
public:
int insert_string(const char *string_in)
{
const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;//定义哈希类型
/*计算lpszString字符串经过解析后应该放入或者查询各表的数据*/
unsigned int nHash = HashString(string_in, HASH_OFFSET);//生成要放入hash表中的数据
unsigned int nHashA = HashString(string_in, HASH_A);//要放入hashA表中的数据
unsigned int nHashB = HashString(string_in, HASH_B);//要放入hashB表中的数据
unsigned int nHashStart = nHash % nTableSize;//计算起始查询位置
unsigned int nHashPos = nHashStart;//初始化实际查询到的位置
while (HashTable[nHashPos].bExists)//发生了碰撞
{
//校验碰撞原因
if (HashATable[nHashPos] == nHashA && HashBTable[nHashPos] == nHashB)
break; //原始数据发生了重复,可能的情况:1.发生了错误,2.我们执行的是查询
else
nHashPos = (nHashPos + 1) % nTableSize;//说明数据没有重复,但原来的位置上有数据,也就是发生了碰撞的情况,所以将实际位置偏移
if (nHashPos == nHashStart)
{
cout<<"表已满,无法插入数据"<<endl;
return 0;
}
}
/*插入的情况*/
if (!HashTable[nHashPos].bExists && (strlen(string_in) < nMaxStrLen))
{
HashATable[nHashPos] = nHashA;
HashBTable[nHashPos] = nHashB;
strcpy(data[nHashPos], string_in);
HashTable[nHashPos].bExists = 1;
cout<<"字符串"<<string_in<<"插入成功,位于"<<nHashPos<<endl;
}
else
{
if(HashTable[nHashPos].bExists)
cout<<"字符串"<<string_in<<"已存在于表中,无法插入"<<endl;
else
cout<<"字符串"<<string_in<<"长度超标,无法插入"<<endl;
}
return nHashPos;
}
int search_string(const char *string_in)
{
const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;//定义哈希类型
/*计算lpszString字符串经过解析后应该放入或者查询各表的数据*/
unsigned int nHash = HashString(string_in, HASH_OFFSET);//生成要放入hash表中的数据
unsigned int nHashA = HashString(string_in, HASH_A);//要放入hashA表中的数据
unsigned int nHashB = HashString(string_in, HASH_B);//要放入hashB表中的数据
unsigned int nHashStart = nHash % nTableSize;//计算起始查询位置
unsigned int nHashPos = nHashStart;//初始化实际查询到的位置
while (HashTable[nHashPos].bExists)//发生了碰撞
{
//校验碰撞原因
if (HashATable[nHashPos] == nHashA && HashBTable[nHashPos] == nHashB)
break; //原始数据发生了重复,可能的情况:1.发生了错误,2.我们执行的是查询
else
nHashPos = (nHashPos + 1) % nTableSize;//说明数据没有重复,但原来的位置上有数据,也就是发生了碰撞的情况,所以将实际位置偏移
if (nHashPos == nHashStart)
cout<<"字符串"<<string_in<<"不在表中"<<endl;
return 0;
}
if(strlen(data[nHashPos]))
{
cout<<"字符串"<<string_in<<"在表中"<<nHashPos<<endl;
return nHashPos;
}
else
cout<<"字符串"<<string_in<<"不在表中"<<endl;
}
/*生成密码表*/
void prepareCryptTable()
{
unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;
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);
cryptTable[index2] = ( temp1 | temp2 );
}
}
}
private:
/*按照dwHashType定义的类型取得字符串lpszFileName的各项hash值*/
unsigned long HashString(const char *lpszFileName, unsigned long dwHashType )
{
unsigned char *key = (unsigned char *)lpszFileName;
unsigned long seed1 = 0x7FED7FED;
unsigned long seed2 = 0xEEEEEEEE;
int ch;
while( *key != 0 )
{
ch = *key++;
seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
}
return seed1;
}
};
void main()
{
CHashForMpq cHashForMpq;
cHashForMpq.prepareCryptTable();
cHashForMpq.insert_string("abcdefghijklmnopqrstuvwxyz");
cHashForMpq.insert_string("abcd");
cHashForMpq.insert_string("ab");
cHashForMpq.insert_string("ab");
cHashForMpq.search_string("abcd");
cHashForMpq.search_string("efd");
getchar();
}