1. 回顧
2. Open Addressing核心思想
2.1 Linear Open Addressing
2.2 Quadratic Open Addressing
3. 延遲刪除(lazy deletion)
4. Open Addressing實現
4.1 基本數據結構
enum Kind {LEGITIMATE,EMPTY,DELETED};
struct HashNode{
ElementType elementValue;
enum Kind kind;
};
struct HashTbl{
int tableSize;
int content;
HashNode* table;
};
HashTbl* hashTable;
4.2 初始化
template<class elementtype="">
void HashTable<elementtype>::initialize(HashTbl*& newHashTable, int minSize)
{
int tableSize=nextPrime(minSize);//尋找下一個比minSize大的質數
try{
newHashTable=new HashTbl;
}catch(std::bad_alloc&){
errorDisplay("new memory failed!",__FILE__,__FUNCTION__,__LINE__);//如果new失敗,報錯
}
try{
newHashTable->table=new HashNode[tableSize];
}catch(std::bad_alloc&){
errorDisplay("new memory failed!",__FILE__,__FUNCTION__,__LINE__);//如果new失敗,報錯
}
for(int i=0;i<tablesize i="" newhashtable-="">table[i].kind=EMPTY;
}
newHashTable->tableSize=tableSize;
newHashTable->content=0;
}
</tablesize></elementtype></class>
4.3 尋找Find
template<class elementtype="">
int HashTable<elementtype>::findInner(HashTbl* _hashTable,ElementType& elementValue)
{
int key=getElementKey(elementValue)%_hashTable->tableSize; //第一次Hash,getElementKey是根據輸入數據獲得一個初始key值,詳細可參考上一章
int hashTimes=0;
while(_hashTable->table[key].kind!=EMPTY && _hashTable->table[key].elementValue!=elementValue){
key=hash2(key,hashTimes)%_hashTable->tableSize; //hash2就是上面所提到的Function,具體見下面
}
return key;
}
template<class elementtype="">
bool HashTable<elementtype>::find(ElementType elementValue)
{
int pos=findInner(hashTable,elementValue);
return hashTable->table[pos].kind==LEGITIMATE;
}
template<class elementtype="">
int HashTable<elementtype>::hash2(int key,int hashTimes)
{
switch(OPEN_ADDRESS){ //根據不同的Open Addressing方法,選擇不同的位移方式
case LINEAR:
return key+hashTimes;
case QUDRATIC:
return key+2*(hashTimes+1)-1;
default:
errorDisplay("OPEN_ADDRESS method error!",__FILE__,__FUNCTION__,__LINE__);
return -1;
}
}
</elementtype></class></elementtype></class></elementtype></class>
4.4 插入Insertion
template<class elementtype="">
bool HashTable<elementtype>::insertInner(HashTbl*& _hashTable, ElementType& elementValue)
{
//rehash
if(loadFactor>MAX_LOAD_FACTOR){ //MAX_LOAD_FACTOR一般取0.5
_hashTable=rehash(_hashTable->tableSize); //rehash的概念在上一章講過
}
int pos=findInner(_hashTable,elementValue);
HashNode& hashNode=_hashTable->table[pos];
if(hashNode.kind==LEGITIMATE) //該值已經存在,無需插入
return false;
else{ //該值不存在,或者已被刪除
hashNode.elementValue=elementValue;
hashNode.kind=LEGITIMATE;
_hashTable->content++;
loadFactor=(double)(_hashTable->content)/(double)(_hashTable->tableSize);
return true;
}
}
template<class elementtype="">
bool HashTable<elementtype>::insert(ElementType elementValue)
{
return insertInner(hashTable,elementValue);
}
</elementtype></class></elementtype></class>
4.5 刪除Remove
template<class elementtype="">
bool HashTable<elementtype>::removeInner(HashTbl* _hashTable,ElementType& elementValue)
{
int pos=findInner(_hashTable,elementValue);
HashNode& hashNode=_hashTable->table[pos];
if(hashNode.kind==LEGITIMATE){ //這個點存在
hashNode.kind=DELETED;
_hashTable->content--;
loadFactor=(double)(_hashTable->content)/(double)(_hashTable->tableSize);
return true;
}
else //這個點不存在,或已被刪除
return false;
}
template<class elementtype="">
bool HashTable<elementtype>::remove(ElementType elementValue)
{
return removeInner(hashTable,elementValue);
}
</elementtype></class></elementtype></class>
4.6 擴充Hash表 rehash
template<class elementtype="">
class HashTable<elementtype>::HashTbl* HashTable<elementtype>::rehash(int currentSize)
{
HashTbl* newHashTable;
initialize(newHashTable,currentSize*10);//擴充一個比原來大十倍的Hash表,這個數字是我簡單設定的,沒有經過考量!
loadFactor=(double)(hashTable->content)/(double)(newHashTable->tableSize);
for(int i=0;i<hashtable->tableSize;i++){
insertInner(newHashTable,hashTable->table[i].elementValue);
}
return newHashTable;
}
</hashtable-></elementtype></elementtype></class>
5. 性能測試
int main()
{
HashTable<int> hashTable(1000000, &getElementKey,&isEqual,HashTable<int>::QUDRATIC,0.49);
clock_t start=clock();
for(int i=0;i<10000000;i++){
int r=rand();
hashTable.insert(r);
}
clock_t finish=clock();
printf("time is %fs\n",(double)(finish-start)/CLOCKS_PER_SEC);
return 0;
}
</int></int>
使用clang++編譯,O3速度優化。測試結果:
time is 2.239344s time is 2.059147s time is 2.318181s