哈希表模板--两种实现方式
哈希表分为开放寻址法和拉链法。时间复杂度近似o(1),一般仅进行添加和查找,一般不删除(用数组标记)。
作用是使较大的定义域 映射到一个较小范围的集合
离散化是一种保持有序性的特殊哈希。
- x mod 10^5(目标小集合长度,取质数冲突概率小)
- 冲突处理
拉链法:用邻接表存储,把e[N]拆成很多个链表。
开放寻址法:仅一个数组,但长度比输入长度(目标小集合)大2,3倍。上厕所找坑位一样,插入时先取模得映射下标k,察看k处是否为空,为空插入,否则k++直到找到空位。查询时find 取模得下标k,查看k处是否为目标x,不为空但不是x则k++,为空则x不存在,不为空为x则true。
例题 : https://www.acwing.com/problem/content/842/
拉链法
#include <iostream>
#include <cstring>
using namespace std;
//拉链法
//开槽范围只需要比输入范围大且最好是质数
const int N=100003;
//h[N]是开的槽位,后三个就是单链表的内容
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] 为head,先将新结点指向head所在结点,再将head指向新结点
h[k]=idx++;
}
bool find(int x){
int k=(x % N + N) % N;
//遍历凹槽位置的单链表,找到x就返回true
for(int i=h[k];i!=-1;i=ne[i]){
if(e[i] == x)
return true;
}
return false;
}
int main(){
int n;
cin>>n;
memset(h,-1,sizeof(h));
while(n--){
string op;
int x;
cin>>op>>x;
if(op=="I") insert(x);
else{
if(find(x)) puts("Yes");
else puts("No");
}
}
return 0;
}
开放寻址法:
#include<cstring>
#include<iostream>
using namespace std;
//开放寻址法
//N取输入数据范围的2,3倍以上,最好是质数可以减少冲突
//null 是定义域之外的数来标记为空
const int N=200003,null =0x3f3f3f3f;
int h[N]; //定义凹槽
int find(int x){
int t=(x % N + N)%N;
while(h[t]!=null && h[t]!=x){ //寻找空位 or找x下标
t++;
if(t==N) t=0;
}
return t; //返回凹槽下标
}
int main(){
memset(h,0x3f,sizeof h);//按字节赋值,int 4字节
int n;
cin>>n;
while(n--){
string op;
int x;
cin>>op>>x;
if(op == "I") h[find(x)]=x;
else{
if(h[find(x)]==null) puts("No");
else puts("Yes");
}
}
return 0;
}