L . 案例5-1.4:字符串关键字的散列映射 [ 问题 9295 ] [ 讨论 ]
Description
给定一系列由大写英文字母组成的字符串关键字和素数 $P$ ,用移位法定义的散列函数$H (Key)$ 将关键字 $Key$ 中的最后3个字符映射为整数,每个字符占5位;再用除留余数法将整数映射到长度为$P$ 的散列表中。例如将字符串AZDEG插入长度为1009的散列表中,我们首先将26个大写英文字母顺序映射到整数0~25;再通过移位将其映射为3×32²+4×32+6=3206;然后根据表长得到3206,即是该字符串的散列映射位置。
发生冲突时请用平方探测法解决。
Input
输入第一行首先给出两个正整数$N$ ($\le 500$)和$P$ ($\ge 2N$ 的最小素数),分别为待插入的关键字总数、以及散列表的长度。第二行给出$N$ 个字符串关键字,每个长度不超过8位,其间以空格分隔。
Output
在一行内输出每个字符串关键字在散列表中的位置。数字间以空格分隔,但行末尾不得有多余空格。
Samples
Input
4 11
HELLO ANNK ZOE LOLI
Output
3 10 4 0
Source
浙大版《数据结构学习与实验指导(第2版)》
单纯的介绍两个坑吧:
平方探测法应该是 pos±i*i进行探测,并不是单纯的+操作(除非题目有要求)
切记新的地址是 newpos = 原来的地址(即输入的地址或者题目要求所求的“首次”地址) ± d^2,而不是oldpos += d^2!!!(即老地址单纯加),整个寻址过程,递增的只有平方间隔d !!!
注意字符串长度可能小于3
judge数组的+1操作,避免sum%p==0 导致后期judge[str]==0,无法判重
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int hash[N];
map<int,int>vis;
map<string,int>judge;
int main(){
int n,p;
cin>>n>>p;
for(int i=1;i<=n;i++){
string str;
cin>>str;
int sum=0;
if(!judge[str]){
for(int j=str.size()-1,e=1;j>=0&&e<=1*32*32;j--,e*=32) um+=(str[j]-'A')*e;
int temp=sum;
int pos=1;
int opr=1;
while(vis[sum%p]){
sum=(temp+pos*pos*opr+p)%p;//这里要排除负数地址情况,否则不会过
opr*=-1;
if(opr>0) pos++;
}
judge[str]=sum%p+1; //+1操作避免sum%p==0 导致后期judge[str]==0,无法判重
vis[sum%p]=1;
}
cout<<judge[str]-1<<" ";//对应的-1操作
}
return 0;
}