AcWing 840. 模拟散列表
原题链接
简单
作者:
满目星河_0
,
2021-03-31 12:30:51
,
所有人可见
,
阅读 114
带注释(超详细)
//哈希数组的大小最好是一个质数。
//算法思想:哈希表就是将一个很大范围的数映射到一个小的数据范围。映射函数就是取模运算。
//对应的两种操作:
//1.插入操作:利用哈希函数,用链表来实现不同的槽上面存储不同的数,初始时空指针用-1表示。
//2.查找操作:利用哈希函数,查找对应槽上面不同的数。
//拉链法的实现:
/*#include<iostream>
#include<cstring>
using namespace std;
const int N=100000;
int idx;
int h[N],e[N],ne[N];
//h数组表示哈希函数的槽
//e数组存放的是每个节点的值
//ne数组表示节点指向的下一个节点
void insert(int x){
int k=(x%N+N)%N; //确保取模后为正数(因为c++中负数取模为复数)
e[idx]=x;
ne[idx]=h[k];
h[k]=idx++; //h[k]这里指向的也是下标。
}
bool search(int x){
int k=(x%N+N)%N;
bool flag=false;
for(int i=h[k];i!=-1;i=ne[i]){
if(e[i]==x){ //在这里必须是e[i],因为i是指的是下标
flag=true;
break;
}
}
return flag;
}
int main(){
int m;
cin>>m;
memset(h,-1,sizeof(h)); //将哈希表初始化为-1
string op;
int a;
while(m--){
cin>>op;
if(op=="I") {
cin>>a;
insert(a);
}
else{
cin>>a;
if(search(a)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}*/
//开放寻址法:只需要开一个哈希数组,不需要再去维护各个槽上面的链表。但是要把哈希数组开的
//大一些,一般是正常所需要的哈希数组的2-3倍,会减少冲突的概率。
//如果在插入的时候冲突了,就在哈希数组中往后面移动一位。
#include<iostream>
#include<cstring>
using namespace std;
const int N=200003, null=0x3f3f3f3f;
//null必须是−109≤x≤109超出题目中所给的这个数据范围的数,代表空。
int h[N];//开的哈希数组的大小一般是正常范围的2-3倍
int find(int x){
int k=(x%N+N)%N;
while(h[k]!=null&&h[k]!=x){
//遇到null或者遇到要找的x时就返回:当遇到null时,表示要插入的位置;
//当遇到x时,表示已将找到。
k++;
if(k==N) k=0;
//如果使用完了一个哈希表的长度,需要使用下一个哈希表,下标重新从0开始
}
return k;//这里的k分别对应上面的两种情况。
}
int main(){
int m;
cin>>m;
memset(h,0x3f,sizeof(h));
//memset是按照字节进行赋值的,int有四个字节,所以是0x3f
string op;
int a;
while(m--){
cin>>op;
if(op=="I") {
scanf("%d",&a);
h[find(a)]=a;
}
else{
scanf("%d",&a);
if(h[find(a)]!=null) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}
//总结:开放寻址法比拉链法更加的方便,但是拉链法会更加好理解。