哈希表
哈希表: 通过键快速查找到对应的值的数据结构。
实现方法: 为了方便实现, 使用模运算实现, 通常除数使用质数, 从而减少哈希冲突的概率
冲突处理:
- 开放寻址法
- 拉链法
拉链法
对于哈希到相同槽位的不同关键字,用一个链表将它们串联起来
cpp
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100003;
int a[N], h[N], ne[N], idx = 1;
//a是存储数据的节点
//h是头节点
//ne是节点的下一个节点的下标
//全部值都共用一个数组,也就是得出下标不同的数据共用一个数组但使用不同的位置
void insert(int x)
{
int k = (x % N + N) % N;
ne[idx] = h[k];
a[idx] = x;
h[k] = idx++;
}
bool query(int x)
{
int k = (x % N + N) % N;
for (int i = h[k]; i != 0; i = ne[i])
if (a[i] == x)
return true;
return false;
}
int main()
{
int n;
cin >> n;
while (n--)
{
char chr;
int x;
cin >> chr >> x;
if (chr == 'I')
insert(x);
else
{
if (query(x))
cout << "Yes\n";
else
cout << "No\n";
}
}
return 0;
}
开放寻址法
空间通常要开大2~3倍
如果下标已经有数据就找下标+1的位置存储数据
cpp
#include <iostream>
#include <cstring> //(注:原文缺少)
using namespace std;
const int N = 300007, null = 0x3f3f3f3f;
int a[N];
int find(int x)
{
int k = (x % N + N) % N;
while (a[k] != null && a[k] != x)
{
k++;
if (k == N)k = 0;
}
return k;
}
int main()
{
int n;
cin >> n;
memset(a, 0x3f, sizeof(a));
while (n--)
{
char chr;
int x;
cin >> chr >> x;
int k = find(x);
if (chr == 'I')
a[k] = x;
else
{
if (a[k] == x)cout << "Yes\n";
else cout << "No\n";
}
}
return 0;
}
字符串哈希方式
字符串前缀哈希法 把字符串看成是一个p进制的数, ( A B C D ) p ( m o d Q ) ( A B C D )_p \pmod Q (ABCD)p(modQ),
- 取值 : 通常取值 P=131或13331, Q= 2 64 2^{64} 264, 用unsigned long long 当溢出的时候就相当于取模。
作用: 方便求任意区间内的哈希值 -> 快速判断两个字符串是否相同
[l,r]-> h ( r ) − h ( l − 1 ) ⋅ p r − l + 1 h(r)-h(l-1) \cdot p^{r-l+1} h(r)−h(l−1)⋅pr−l+1
cpp
#include <iostream>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010, P = 131;
char c[N];
ULL h[N], p[N];
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
int n, m;
cin >> n >> m >> c + 1;
p[0] = 1;
for (int i = 1; i <= n; i++)
{
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + c[i];
}
while (m--)
{
int l1, r1, l2, r2;
cin >> l1 >> r1 >> l2 >> r2;
if (get(l1, r1) == get(l2, r2))
cout << "Yes\n";
else
cout << "No\n";
}
return 0;
}