acwing基础课ch2-哈希表
约 1107 字
预计阅读 3 分钟
哈希表
- 将一个复杂的数据结构进行映射。
- (key-value)pair的关系。
哈希表基本元素
- key-value映射
- 哈希函数
- 哈希冲突解决方法
哈希函数
- 一般取模(x%MOD)
- MOD是大于数据规模的最小质数
哈希冲突
- 不同的key通过哈希函数后产生了相同的value(映射)。
拉链法
- 产生了冲突之后,将产生哈希冲突的值用链表的方式存储在相应的idx之后
- 插入:在哈希值的链表上插入一个值。
- 查找:找到哈希值,在哈希值对应的链上查找。
- 删除:删除链表的一个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#include <iostream>
const int N = 1e5+10;
using namespace std;
struct Listnode{
int val;
Listnode* next;
Listnode(int x = 0, Listnode* ne = nullptr):val(x), next(ne) {}
};
// 哈希值
Listnode* h[N] = {nullptr};
void insert(int x){
// 负数情况
int t = (x % N + N) % N;
Listnode* add = new Listnode(x, nullptr);
if(h[t] == nullptr){
h[t] = add;
}else{
add -> next = h[t] -> next;
h[t] -> next = add;
}
}
bool find(int x){
int t = (x % N + N) % N;
Listnode* root = h[t];
while(root != nullptr){
if(root -> val == x){
return true;
}
root = root -> next;
}
return false;
}
int main(){
int n;
cin >> n;
while(n--) {
char op;
int x;
cin >> op >> x;
if(op == 'I'){
insert(x);
}else{
if(find(x)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
|
开放寻址法
- 产生了冲突之后,向后查找直到找到一个位置value没有任何key存在在这个位置
- 添加:
- 查找:计算哈希值,查找哈希序列,如果遇到目标值,返回该目标值的下标。否则继续查找到一个合适位置。
- 删除:打一个特殊标记,不需要真的删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
const int N = 2e5+3;
const int null = 0;
int h[N], n;
// 开放寻址法
int find(int x){
// 负数取余数仍是负数
// 处理负数的情况
int t = (x % N + N) % N;
// 直到遇到空的节点,结束搜素
while(h[t] != null){
// 如果找到目标值返回目标值的索引
if(h[t] == x){
break;
}
t ++;
if(t == N - 1){
t = 1;
}
}
// 如果没找到目标值,返回它应该在的位置
return t;
}
int main(){
cin >> n;
while(n-- ){
char op;
int x;
cin >> op >> x;
int t = find(x);
if(op == 'I'){
h[t] = x;
}else{
if(h[t] == x) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
|
字符串哈希
字符串前缀哈希法
- 将字符串转换为一个k进制的数。
- 然后将这个数取余数可以得到这个字符串的哈希值
- 注意不能有字母映射为0,对P,Q取经验值时不会存在哈希冲突。

- 首先求出一个字符串所有前缀的哈希值
- 然后可以根据前缀的哈希值就可以在$O(1)$时间内求出任一子串的哈希值
- $h[l, r] = h[r] - h[l-1] * p ^{(r - l + 1)}$

字符串哈希
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
#include <iostream>
using namespace std;
typedef unsigned long long ull;
const int N = 1e5+10, P = 131;
ull h[N], p[N];
// 返回前缀和
ull find(int l, int r){
return h[r] - h[l - 1] * p[r - l + 1];
}
int main(){
int n, m;
cin >> n >> m;
string s;
cin >> s;
p[0] = 1;
// 计算前缀
for(int i = 1; i <= n; i++){
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + s[i - 1];
}
while(m-- ){
int l1, r1, l2, r2;
cin >> l1 >> r1 >> l2 >> r2;
if(find(l1, r1) == find(l2, r2)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
|