哈希表
适合将定义域很大的数据映射到值域较小的集合。是一般意义上的哈希,离散化是一种特殊的哈希,需要保序,哈希函数需要单调递增。
x∈(10−9,109),h(x)∈(0,105)
哈希函数一般为:h(x)=x \mod 质数
质数应尽可能离 2n 要远,这样冲突的概率最小。
存储结构
开放寻址法
只使用一个一维数组,经验值开辟 2~3 倍元素个数的数组空间。
拉链法
开一个一维数组,长度为值域大小。每次算出一个哈希值 h[x] = y
,就在 y 的位置上开一个链表,在链表末尾记录 x 的值。
查询某个数 x 是否在哈希表中,首先计算出哈希值 h[x] = y
,然后遍历哈希值对应的数组位置 y 上的链表,查看链表中是否存在 x。
总结:一个数组,拉了很多链表。数组插槽编号对应的是哈希值,数组插槽内容对应的是链表节点编号。链表节点中存的是原始数据值。
字符串哈希方式
将字符串看成一个 p 进制数。
例如:“ABCD”
hash((ABCD)p)=(1∗p3+2∗p2+3∗p1+4∗p0)modQ
p 取 131 或 13331。
Q 取 264。
实际写代码时,A B C D 取他们的 ascii 码就可以,不必写成上面的 1 2 3 4。
这样可以在 99% 的情况下避免冲突。
注意:
- 不能把某个字母映射成 0。
- 不考虑冲突。
例题
拉链法
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
| #include <cstring> #include <iostream> using namespace std; const int N = 100003;
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 () { int n; memset(h, -1, sizeof h); scanf("%d", &n); 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; }
|
开放寻址法
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
| #include <iostream> #include <cstring> using namespace std;
const int N = 200003, null = 0x3f3f3f3f; int h[N];
int find(int x) { int k = (x%N+N)%N; while(h[k] != null && h[k] !=x) { k++; if(k==N) k=0; } return k; }
int main() { int n; scanf("%d", &n); memset(h, 0x3f, sizeof h); while(n--) { char op[2]; int x; scanf("%s%d", op, &x);
int k = find(x); if(*op == 'I') h[k] = x; else { if(h[k] != null) puts("Yes"); else puts("No"); } } return 0; }
|
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
| #include <iostream> using namespace std;
const int N = 100010, P = 131;
typedef unsigned long long ULL;
int n, m; char str[N];
ULL h[N], p[N];
ULL get(int l, int r) { return h[r] - h[l-1]*p[r-l+1]; }
int main() { scanf("%d%d%s", &n, &m, str + 1); p[0] = 1; for(int i=1;i<=n;i++) { p[i] = p[i-1] * P; h[i] = h[i-1] * P + str[i]; } while(m--) { int l1, r1, l2, r2; scanf("%d%d%d%d", &l1, &r1, &l2, &r2); if(get(l1, r1) == get(l2, r2)) puts("Yes"); else puts("No"); } return 0; }
|