linear hash
一,在介绍linear hash 之前,需要对动态hash和静态hash这两个概念做一下解释:
静态hash:是指在hashtable初始化得时候bucket的数目就已经确定了,当需要插入一个元素的时候,通过hash函数找到对应的bucket number,之后插入即可。不论用什么冲突解决方法,当插入的元素越来越多时,在这个hash表中查找元素的效率会变的越来越低。
动态hash:是指在hashtable的bucket的数目不是确定的,而是会根据插入元素的多少而实现动态的增减,当元素变多得时候,bucket会动态增加,这样就可以解决静态hash的查找效率低得问题。当元素变少得时候,bucket会动态减少,从而减少空间的浪费。linear hash就是一种动态hash。
二。linear hash实现.
对于hash操作,主要有insert, find, erase三个操作,下面对linear_hash的3个操作做一些解析:
1. Find.
对于查找操作,目的是输入key值,找出对应的卫星数据的值,这一操作和其他hash操作一样。
bool find(KeyType iKey, DataType& oData)
{
int lKey = hashfunc(iKey);
if(lKey < 0 || lKey >= numBucket) return false;
bucketIter iter = mhashTable[lKey].begin();
for(; iter != mhashTable[lKey].end(); iter ++)
{
if(iter->first == iKey)
{
oData = iter->second;
return true;
}
}
return false;
}
2. Insert操作。
对于插入操作,客户端程序输入key值和卫星数据,进行这一操作,会增加Linearhash中的元素个数numElement,当Linearhash的bucket负载(numElements/numBuckets)超过一定值,需要动态的增加Bucket数,增加一个bucket, 接着需要把一个特定的bucket上的element分一部分到这个new 的bucket上。
bool insert(KeyType iKey, DataType& iData)
{
int lKey = hashfunc(iKey);
if(lKey < 0 || lKey >= numBucket) return false;
//把这个element插入到对应的bucket(mHashTable[lKey])里面
mhashTable[lKey].push_back(make_pair(iKey, iData));
numElement ++;
//计算现在Container的负载= 现在的元素个数/bucket数目
double loadFctr = (double)numElement / numBucket;
//如果负载操作最大的负载数,那么需要做extend操作。
//目的是增加bucket数,接着均分bucket上得element
if(loadFctr >= maxloadfctr)
{
Extend();
}
return true;
}
void Extend()
{
//计算出需要被均分的bucket位置mhashTable[oldPos].
//计算出新的bucket位置mhashTable[newPos].
int oldpos = p;
int newpos = numBucket;
mhashTable.resize(++ numBucket);
//接着调整Container的状态,
//当p增加到最大的maxp的值时,需要成倍的增加maxp数,同时p回归为0
p = p + 1;
if(p == maxp)
{
maxp *= 2;
p = 0;
}
//接下来把mhashtable[oldpos]这个bucket中的元素按照一定的规则分配到nhashTable[newPos]内,一部分会留在原来的mhashtable[oldpos]中
bucketIter iter = mhashTable[oldpos].begin();
for(; iter != mhashTable[oldpos].end(); )
{
if(hashfunc(iter->first) == newpos)
{
mhashTable[newpos].push_back(make_pair(iter->first, iter->second));
iter = mhashTable[oldpos].erase(iter);
}
else
iter ++;
}
}
3. Erase操作
对于erase操作,客户端程序给定key值,要求contianer删除其中和key值相同的元素。同时需要减少numElement数,当Linearhash的bucket负载(numElements/numBuckets)减少到一定值,需要动态的减少Bucket数,减少一个bucket, 同时需要把这个减少的bucket中的所有元素还原到原来的oldBucket中。
bool erase(KeyType iKey)
{
int lKey = hashfunc(iKey);
if(lKey < 0 || lKey >= numBucket) return false;
bool isfound = false;
//在mhashTable[lKey]这个bucket中查找这个lKey值
bucketIter iter = mhashTable[lKey].begin();
for(; iter != mhashTable[lKey].end(); )
{
if(iter->first == iKey)
{
iter = mhashTable[lKey].erase(iter);
isfound = true;
break;
}
else
{
iter ++;
}
}
//如果找到了,需要减少numElement值,调增bucekt数
if(isfound)
{
numElement --;
double loadFctr = (double)numElement / numBucket;
if(loadFctr <= minloadfctr && numBucket > FIRSTBUCKETS)
{
Shrink();
}
return true;
}
return false;
}
void Shrink()
{
//调增状态
p--;
if(p < 0)
{
maxp /= 2;
p = maxp -1;
}
//把mhashtable[numBucekt-1]中的元素全部insert到mhashtable[p]这个bucket中,
//同时调增mhashtable的大小。
mhashTable[p].insert(mhashTable[p].end(), mhashTable[numBucket-1].begin(), mhashTable[numBucket-1].end());
mhashTable[numBucket - 1].clear();
mhashTable.resize(--numBucket);
}
三.于STL::map和STLEXT::hash_map做了一下性能比较。
测试结果如下:
Linearhash insert time consume: 160
Linearhash find time consume: 50
Linearhash erase time consume: 70
map insert time consume: 80
map find time consume: 40
map erase time consume: 110
hash_map insert time consume: 150
hash_map find time consume: 40
hash_map erase time consume: 2130