携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
AcWing 840. 模拟散列表
维护一个集合,支持如下几种操作:
I x,插入一个数 x;Q x,询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果。
输入格式
第一行包含整数 N,表示操作数量。
接下来 N 行,每行包含一个操作指令,操作指令为 I x,Q x 中的一种。
输出格式
对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No。
每个结果占一行。
数据范围
1 ≤ N ≤ 10^5
−10^9 ≤ x ≤ 109
输入样例:
5
I 1
I 2
I 3
Q 2
Q 5
输出样例:
Yes
No
思路
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
拉链法图解
开放寻址法图解
使用哈希计算映射到数组中的位置,如果当前位置有数字,被占领,就向后移动,直至有空缺位置,如果移动到最后一个位置仍然没有空缺,就从头开始重新遍历寻找,
一般哈希模板
拉链法
int h[N], e[N], ne[N], idx;
// h[]散列表保存头节点的下标
// e[]保存值,ne[]保存前一个值的下标,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]) //循环遍历从头节点向下遍历,遍历ne数组的存储的指向地址
if (e[i] == x)
return true;
return false;
}
开放寻址法
int h[N];
// 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
int find(int x){
int t = (x % N + N) % N;
while (h[t] != null && h[t] != x){
t ++ ;
if (t == N) t = 0;
}
return t;
}
ac代码
开放寻址法代码
#include <cstring>
#include <iostream>
using namespace std;
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){
t ++ ;
if (t == N) t = 0;
}
return t;
}
int main(){
memset(h, 0x3f, sizeof h);
int n;
scanf("%d", &n);
while (n -- ){
char op[2];
int x;
scanf("%s%d", op, &x);
if (*op == 'I') h[find(x)] = x;
else{
if (h[find(x)] == null) puts("No");
else puts("Yes");
}
}
return 0;
}
拉链法代码
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100003; //是大于10000的第一个素数
int h[N], e[N], ne[N], idx;
//h数组是哈希函数的一维数组,e数组是链表中存的值,ne数组是指针存的指向地址,idx是当前指针
void insert(int x){
int k = (x % N + N) % N; //计算哈希映射,包含对负数的处理
e[idx] = x; //对于链表的处理
ne[idx] = h[k]; //表示指向数组中的哪一个位置
h[k] = idx ++ ; //储存哈希后映射到k的数 的链表的头结点在e数组的下标
}
bool find(int x){
int k = (x % N + N) % N;
for (int i = h[k]; i != -1; i = ne[i])//如果头节点不为-1,表示有节点,然后遍历
if (e[i] == x)
return true;
return false;
}
int main(){
int n;
scanf("%d", &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;
}