有一个简单的Hash表,采用一位数组直接存放元素,Hash函数是个对表长取模,冲突解决采用线性探测。
这样的Hash表较容易实现,查找和插入方法都按照先哈希再探测的步骤就可以了,但删除表中的元素稍微复杂。
因为表中有冲突的元素存在,这些元素应用了探测方法被放置在其他位置上,若删除表中一个元素可能对这些元素的查找造成影响,可能使查找元素的正常过程中断。这里称由于删除一个元素给哈希表造成一个gap。我们称关键字key的哈希值为key的哈希位置;称使用探测技术重新安排位置的元素为后置元素。
为了避免事情的发生,我们需要fill in gaps直到所有的元素都能被找到。下面是一段简单的代码。
//假设哈希表Hash中存放结构体student的相关信息,使用学号id作为关键字.
//称学号为id的元素为元素id。id==0表示该哈希表项未被占用。
int find(int id);//返回元素id在表中的位置
int hash(int id);//计算元素id的哈希值
void delete(int id){
int i=find(id);
for(;;){
Hash(i).id = 0; //删除元素i,产生一个gap。
int j=i; //j存放gap的位置,下面要从gap后面选出一个后置元素来填充gap。
for(;;){ //这里选择离gap最近的那个
i= (++i)%Hash_Table_Size;
if(Hash(i).id == 0){ //遇到了未用的slot,因从gap到该slot段的后置元素都被处理得当,不会再有新的gap产生
return; //所以方法可以结束了。
}
int r=hash(i); //若当前元素的哈希位置r位于gap和其当前位置i之间,则不选择该元素。
if(j<r && r<=i) //因为该元素本来就应该在gap之后,是不能用它来填充个gap的,它也不受gap影响。
continue; //三个if语句考虑到了i,j的位置关系,即i,j的大小。三个条件都限制了r要在i和j之间。
if(j>i && j<r)
continue;
if(j>i && r<=i)
continue;
break; ///元素的哈希位置在允许的范围之外,即它为受影响的后置元素。则:
}//for
Hash(j)=Hash(i); //选择该元素填充gap。并删除该元素产生一个新gap
}//for
}//delete
这只是一种最为简单的Hash表实现。为避免这样删除的麻烦,可以采用链表法或设置公共溢出区来解决冲突。
有两篇不错的文章:
哈希表的一个实现:http://hi.baidu.com/wihate/blog/item/e0330b7a7a2e9fee2e73b3ae.html
c++实现的一个哈希表类:http://hi.baidu.com/wihate/blog/item/d537ba01070352d5277fb5dc.html
希望以后继续学习哈希表。