关于hash算法的应用是十分广泛的,其中的最简单的原因就是我们生活的这个时代每天都在产生着巨大复杂数据,但是对于我们有价值的数据的挖掘和存储一直是一个难点。如何把我们找到和我们密切相关的且有价值的数据一直是计算机科学面临的关键问题。hash算法从某种角度讲,其实就是为了解决这一问题,尽管效果会因具体的问题和数据体积而参差不齐。所以有必要对hash算法做一个学习,这里是自己的一点小纪录。
先从数据结构的散列开始,Hash Table由散列实现,散列是一种用于“以常数平均时间来执行插入,删除和查找”的技术。
散列(hasing)的核心其实就是把我们的信息项,又叫key映射到hashtable中的不同位置中去。所以这里的有两个直接的问题需要解决,一是映射函数如何设计,二是当不同的key带人到hash fuction后得到的存储位置相同怎么办(collision)?
ok,现在先看第一个问题:hash fuction?
一般的方法是针对int型数据,我们直接对其用存储单元大小将他们分别取余来存储。但是有一个数学的问题会出现,当我们用来存储的内存即hashtable大小是一些非质数时比如10,9等,又当key为带零的整数或是可以被9整除的数时,这种hash function的结果往往等于0,而发生大量冲突。所以在hashtable的大小size时,往往采用数素来定义,ok,这里也可以说明在数学中一下求最大数素或和研究数素性质的猜想的重要作用了,呵呵~
ok,我们以int型数据和string型数据为例来,做一个简单的hash function:
Typedef string elemType;//int
int Hash(const elemType &key,int TabSize){
int dataNumed=0;
for(int i=0;i<TabSize;i++)
dataNumed+=key[i];
return dataNumed%TabSize;
}
其实上面的hash function当TabSize很大时,我们往往不能保证数据存储的分布均匀,甚至仍会有很多冲突发生。
那么如何设计hash函数呢?那首先要明确问题处在哪里,这里我们把hash函数的问题先列出来:1.尽量不让key发生collision。2.尽量让key在hash table中均有分布,即不要浪费存储资源。
ok,还是上面的string的hashfunction,我们对其进一步改造,希望hash 的key值统计时可以尽量充满tablesize,同时要注意和利用计数溢出的情况:
Typedef string elemType;
int Hash(const elemType &key,int size){
int count=0;
for(int i=0;i<size;i++)
count=(24+10+1)*count+key[i];
int hashval=0;
hashval=count % size;
if(hashval<0) hashval+=size;
return hashval;
}
ok,下一步,我们就来看看第一个问题,关于collision的解决方法.