模板题:https://www.acwing.com/problem/content/842/
拉链法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100003; // 取大于1e5的第一个质数,取质数冲突的概率最小
int 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] = 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;
}
int main()
{
scanf("%d",&n);
memset(h,-1,sizeof(h)); // 空指针一般用 -1 来表示
while(n--)
{
char op[2];
int x;
scanf("%s%d",op,&x);
if(op[0] == 'I') insert(x);
else
{
if(find(x)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
开放寻址法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
// 开放寻址法一般开 数据范围的 2~3倍, 这样大概率就没有冲突了
// 大于数据范围的第一个质数
// 规定空指针为 null 0x3f3f3f3f
const int N = 200003,null = 0x3f3f3f3f;
int n;
int h[N];
int find(int x)
{
int k = (x % N + N) % N;
while(h[k] != null && h[k] != x)
{
k++;
if(h[k] == N) k = 0;
}
return k; // 如果这个位置是空的, 则返回的是他应该存储的位置
}
int main()
{
scanf("%d",&n);
memset(h,0x3f,sizeof(h)); // 规定空指针为 0x3f3f3f3f
while(n--)
{
char op[2];
int x,k;
scanf("%s%d",op,&x);
k = find(x);
if(op[0] == 'I') h[k] = x;
else
{
if(h[k] == x) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
为什么哈希函数要模质数
概念与公式
设我们通过哈希函数得到的未取模的值为
X
X
X ,一质数模数为
a
a
a ,非质数模数为
b
b
b ,
X
X
X 对
a
a
a 取模后的结果为
Y
a
Y_a
Ya,对
b
b
b 取模后的结果为
Y
b
Y_b
Yb
则有
Y
a
≡
X
(
m
o
d
a
)
\qquad \qquad \qquad \qquad \quad Y_a ≡ X\ (mod\ a)
Ya≡X (mod a)
Y
b
≡
X
(
m
o
d
b
)
\qquad \qquad \qquad \qquad \quad Y_b ≡ X\ (mod\ b)
Yb≡X (mod b)
c
(
x
m
o
d
y
)
=
(
c
x
)
m
o
d
(
c
y
)
\qquad \qquad \qquad \quad c(x\ mod\ y) = (cx)\ mod\ (cy)
c(x mod y)=(cx) mod (cy)
(
a
+
b
)
m
o
d
p
=
(
a
m
o
d
p
+
b
m
o
d
p
)
m
o
d
p
\qquad \qquad \qquad (a+b)\ mod\ p=(a\ mod\ p+b\ mod\ p)\ mod\ p
(a+b) mod p=(a mod p+b mod p) mod p
假设所有X随机出现,则有
- 模质数时: Y a ∈ [ 0 , a − 1 ] , 均 匀 分 布 Y_a∈[0,a−1],均匀分布 Ya∈[0,a−1],均匀分布
- 模合数时: Y b ∈ [ 0 , b − 1 ] , 均 匀 分 布 Yb∈[0,b−1],均匀分布 Yb∈[0,b−1],均匀分布
假设X成公差为m的等差数列出现,且m与b存在公因数c,则有
- 模质数时:
记 首 项 为 X 1 , 第 i 项 为 X i , 第 i 项 取 模 后 得 到 Y i , 则 记首项为X_1,第i项为X_i,第i项取模后得到Y_i,则 记首项为X1,第i项为Xi,第i项取模后得到Yi,则
Y i = ( X 1 + ( i − 1 ) m ) m o d a Y_i = (X_1+(i−1)m)\ mod\ a Yi=(X1+(i−1)m) mod a
= ( X 1 m o d a + ( ( i − 1 ) m ) m o d a ) m o d a \ \ \ \ \ =(X_1\ mod\ a+((i−1)m)\ mod\ a)\ mod\ a =(X1 mod a+((i−1)m) mod a) mod a
= ( Y 1 + k i ) m o d a , k i ∈ [ 0 , a ) \ \ \ \ \ =(Y_1+k_i)\ mod\ a\ \ \ \ \ \ ,ki∈[0,a) =(Y1+ki) mod a ,ki∈[0,a) - 模合数时:
Y i = ( X 1 + ( i − 1 ) m ) m o d b Y_i =(X_1+(i−1)m)\ mod\ b Yi=(X1+(i−1)m) mod b
= ( X i m o d b + ( ( i − 1 ) m ) m o d b ) m o d b \ \ \ \ \ =(X_i\ mod\ b+((i−1)m)\ mod\ b)\ mod\ b =(Xi mod b+((i−1)m) mod b) mod b
= ( Y 1 + ( i − 1 ) ( m c ) m o d ( b c ) ) m o d b \ \ \ \ \ =(Y_1+(i−1)(\frac{m}{c})\ mod\ (\frac{b}{c}))\ mod\ b =(Y1+(i−1)(cm) mod (cb)) mod b
= ( Y 1 + k i ) m o d b , k i ∈ [ 0 , b c ) \ \ \ \ \ =(Y_1+k_i)\ mod\ b\ \ \ \ \ \ ,k_i∈[0,\frac{b}{c}) =(Y1+ki) mod b ,ki∈[0,cb)
可见 Y i Y_i Yi 取值范围缩小到了原来的 1 c \frac{1}{c} c1,即成等差数列的 X X X 每 b c \frac{b}{c} cb 个数据就会出现一次冲突