1.建立哈希函数(由关键字集合到数组下标集合的映射),理想情况为单射。
2.往往难以构建单射,这就需要遇到这种情况:“装填数据时,利用哈希函数计算出的地址已被占用”时,做出相应的调整。通常有4种方法:
法1,探测序列法
search[100]=[-1,1,-2,2……]若遇到空间占用,向上移动1,若仍被占用,向下移动1,……依次类推。
注意:要记录探测序列使用到了哪一个,不妨记其下标k。因为后续查找时,如果使用到了k仍然没有找到关键字,则查找失败。
typedef struct Hash{
string inf;
};
int main(){
//freopen("/config/workspace/answer/test","r",stdin);
int n;
cin>>n;
int longestsearch=0;//记录最后一个试探标号
Hash hash[10];
for(int i=0;i<10;i++){
hash[i].inf="#";
}
for(int i=0;i<n;i++){
string key;
cin>>key;
int num=0;
for(int j=key.size()-1;j>=key.size()-4;j--){
num+=(int(key[j])-'0');
}
num=num%10;//哈希函数运算结果存入num;
int put=0;
longestsearch=0;
while(hash[num+put].inf!="#"){
put++;
if(hash[num+put].inf=="#")
{longestsearch=put;
break;
}
else if(hash[num-put].inf=="#")
{ longestsearch=-put;
break;
}
}
hash[num+longestsearch].inf.append(key);
}
//输出哈希表
for(int i=0;i<10;i++){
if(hash[i].inf!="#"){
for(int j=1;j<hash[i].inf.size();j++){
cout<<hash[i].inf[j];
}
}
else
cout<<"#";
cout<<endl;
}
return 0;}
法2,二次散列
建立两个哈希函数H1,H2,若装填数据时,使用H1计算出的地址已被占用,则使用H2计算,存入H2.
查找时,使用H1计算地址没有关键字,失败。若存入数据不是关键字,则使用H2计算地址,若地址没有数据,失败;若有数据,但不是关键字,失败。
注意:该方法不适用于装填数据存在两个数据元素,两个哈希函数计算结构一样的数据。
法三,链式存储
地址存放一个指针,指针指向一个节点,该节点数据域是记录第一个通过H 计算结果为该地址的数据元素,指针域存放另一个指针,指向第二个通过H计算结果为该地址的数据元素(尾插法)。
//哈希节点和哈希表,构成哈希表-链表数据结构
typedef struct HashNode{
string Inf;
HashNode* next;
};
typedef struct HashTabel{
HashNode*first;
};
//哈希函数用于计算直接映射
int hashf(string key){
int num=0;
for(int i=key.size()-1;i>key.size()-5;i--)
num+=(key[i]-'0');
return num%10;
}
//将映射成index的key放入table的指的位置
void place(string key,int index,HashTabel tabel[]){
HashNode* p=new HashNode;
p->Inf=key;
p->next=tabel[index].first;
tabel[index].first=p;
}
int main(){
//freopen("/config/workspace/answer/test","r",stdin);
int n;
HashTabel tabel[30];
cin>>n;
//初始化哈希表
for(int i=0;i<10;i++){
tabel[i].first=NULL;
}
for(int i=0;i<n;i++){
string key;
cin>>key;
int index=hashf(key);
place(key,index,tabel);
}
//输出
for(int i=0;i<10;i++){
if(tabel[i].first!=NULL)
{
HashNode*p=tabel[i].first;
while(p){
cout<<p->Inf<<" ";
p=p->next;
}
}
else
cout<<'#';
cout<<endl;
}
return 0;}
法四,公共溢出区域
分为基本区,溢出区。通过H 计算数据元素的对应地址存入,若空间占用,则存入该基本区对应溢出区。
找到基本区,只要通过(下标相同则能找到溢出区)
(表述一个算法思路的自然语言多种多样,但是笔记应该更新为和算法代码能够建立直接对映的语言)