【概念】
散列表(Hash table,也叫哈希表)是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数(哈希函数),存放记录的数组称做散列表。
一.存储结构
1.插入
2.搜索
3.删除
【分析】
1.数组模拟,有两种方法解决冲突。
(1) 开放寻址法
只需要开一个数组,找到x映射的位置,如果当前位置有数,就继续往后找,直到找到一个空的位置,插入。
(2) 拉链法(HashMap用的就是这种,也叫线性探测)
需要开一个数组和链表,每当有冲突,就在当前位置的链表上添加一个数。
attention
这两种方法的删除操作都是另开一个bool数组,将要删除的数标记即可。
!!!图里有个地方写错了,h最后位置是 10^5-1
【代码1 开放寻址法】
#include <cstring>
#include <iostream>
using namespace std;
const int N=100003;
int h[N],null=0x3f3f3f3f;//用一个不在x的范围内的数来判断某位置是否有数
int find(int x){
int k=(x%N+N)%N;
while(h[k]!=null&&h[k]!=x){
k++;//没有找到x,++
if(k==N) k=0;//走到头了,重新做人
}
return k;
}//返回的是x的位置或者x应该在的位置
int main(){
int n;
cin>>n;
memset(h,0x3f,sizeof(h));//于是初始化为0x3f
while(n--){
char op[2];
int x;
scanf("%s%d",op,&x);
int k=find(x);
if(*op=='I') h[k]=x;//该去哪去哪
else{
if(h[k]!=null) puts("Yes");//该位置有数
else puts("No");
}
}
return 0;
}
【代码2 拉链法】
#include <cstring>
#include <iostream>
using namespace std;
const int N=100003;
int h[N],e[N],ne[N],idx;
void insert(int x){
int k=(x%N+N)%N;
e[idx]=x;
ne[idx]=h[k];
h[k]=idx++;
}
bool find(int x){
int k=(x%N+N)%N;
for(int i=h[k];i!=-1;i=ne[i]){
if(e[i]==x)
return true;
}
return false;
}//标记x是否在某位置
int main(){
int n;
cin>>n;
memset(h,-1,sizeof(h));
while(n--){
char op[2];
int x;
scanf("%s%d",op,&x);
if(*op=='I') insert(x);
else{
if(find(x)) puts("Yes");
else puts("No");
}
}
return 0;
}
二.字符串哈希方式
字符串前缀哈希法
【浅浅介绍】
把字符串变成一个p进制数字(哈希值),实现不同的字符串映射到不同的数字。
对形如 X1X2X3⋯Xn−1XnX1X2X3⋯Xn−1Xn 的字符串,采用字符的ascii 码乘上 P 的次方来计算哈希值。
映射公式 (X1×Pn−1+X2×Pn−2+⋯+Xn−1×P1+Xn×P0)modQ
【分析】
1. 因为一个字符串可能非常非常长,因此我们可以把前n个字符映射的数看作一个p进制的数
其中P一般取131或13331,Q一般取2^64(经验值)。
按道理来讲,我们的人品应该足够好,不存在冲突。但是要注意字符不能映射成0,否则有可能出现冲突。
2.
前缀和公式 h[i+1]=h[i]×P+s[i]h[i+1]=h[i]×P+s[i] i∈[0,n−1]i∈[0,n−1]
区间和公式 h[l,r]=h[r]−h[l−1]×Pr−l+1
【代码】
#include <iostream>
using namespace std;
typedef unsigned long long ull;
const int N=100010,P=131;
ull h[N],p[N];//p用来表示p的几次方
int n,m;
char s[N];
ull get(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
int main(){
scanf("%d%d%s",&n,&m,s+1);
p[0]=1;
for(int i=1;i<=n;i++){
p[i]=p[i-1]*P;
h[i]=h[i-1]*P+s[i];
}
while(m--){
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else puts("No");
}
return 0;
}