之前有写过一篇hash表,不过那是非常久远的时候了,应该是大一刚学一个学期的时候的成果,后来也就不那样写了,后来从xiaoxin那里学习了hash的写法,比较容易用也比较方便多hash,就这样。
分别按照下标从0和从1开始写了一遍。
在Hash结构体中
B是基,要求大于出现的数(如对于字符串应该大于127),可用171、191
mod是模数,最好是一个大素数,如1e9+7、1e9+9
Base是预处理出的B的幂,Base[i]表示B的i次幂
Has是前缀Hash数组
1 #include <bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 #define MP make_pair
5 #define PB push_back
6 const int mod = 1e9 + 7;
7 const double eps = 1e-8;
8 const int INF = 0x3f3f3f3f;
9 const int maxn = 1e5 + 5;
10 const int maxm = 1e6 + 5;
11
12 struct Hash{
13 ll B,mod,len,Has[maxn],Base[maxn];
14
15 void init(char *s, int _len, ll _B, ll _mod){ // s[0] 开始
16 B = _B; mod = _mod; len = _len;
17 Base[0] = 1; Has[0] = 0;
18 for(int i=1;i<=len;i++){
19 Base[i] = Base[i-1]*B%mod;
20 Has[i] = (Has[i-1]*B + s[i-1])%mod;
21 }
22 }
23
24 ll gethash(int l,int r){ // s[l]~s[r]
25 l++; r++;
26 return ((Has[r] - Has[l-1] * Base[r-l+1] % mod) + mod) % mod;
27 }
28 };
29
30 struct Hash{
31 ll B,mod,len,Has[maxn],Base[maxn];
32
33 void init(char *s, int _len, ll _B, ll _mod){ // s[1] 开始
34 B = _B; mod = _mod; len = _len;
35 Base[0] = 1; Has[0] = 0;
36 for(int i=1;i<=len;i++){
37 Base[i] = Base[i-1]*B%mod;
38 Has[i] = (Has[i-1]*B + s[i])%mod;
39 }
40 }
41
42 ll gethash(int l,int r){ // s[l]~s[r]
43 return ((Has[r] - Has[l-1] * Base[r-l+1] % mod) + mod) % mod;
44 }
45 };
调用时初始化都为:
Hash H;
H.init(s, len, 171, mod);
这种形式,其中 s 是字符数组名,len是字符串长度,171为自己指定的基,mod是自己指定的大素数。
常见写法也有通过自然溢出来完成取模的,此时就去掉所有的mod操作,将所有 ll 改为 ull 即可。