哈希表模板
拉链法
const int SZ = 100007;
struct hash_table
{
int head[SZ], next[SZ], key[SZ], val[SZ];
int cnt;
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
int hash(int k)
{
return (k % SZ + SZ) % SZ;
}
int count(int k)
{
int hu = hash(k);
for(int i = head[hu]; i != -1; i = next[i])
if(key[i] == k)
return i;
return -1;
}
int& operator[](int k)
{
int idx = count(k);
if(idx != -1){
return val[idx];
}else{
int hu = hash(k);
key[cnt] = k;
next[cnt] = head[hu];
head[hu] = cnt;
return val[cnt++];
}
}
}tb;
字符串哈希
先将字符串转化为一个数再进行Hash,把字符串看作一个 \(p\) 进制的数且保证 \(p\) 大于所有字符的 \(ACSII\) 码即可,在这里我们取 \(p=131\)
自然溢出法
与模数为 \(2^{64}\) 的单Hash法相同
const int BASE = 131;
ull hashs(string s)
{
int len = s.size();
ull res = 0;
for(int i = 0; i < len; i++)
res = res * BASE + s[i];
return res;
}
单Hash法
模数选择一个 \(10^{18}\) 的质数防止冲突
const int BASE = 131;
const ull MOD = 2123704413013795711;
ull hashs(string s)
{
int len = s.size();
ull res = 0;
for(int i = 0; i < len; i++)
res = (res * BASE + s[i]) % MOD;
return res;
}
双Hash法
对一个字符串进行两次模数不同的单Hash,对于两个不同的字符串,只有当他们两次Hash的结果都相等时才会冲突,最为稳妥的做法
const int BASE = 131;
const int MOD1 = 19260817;
const int MOD2 = 19660813;
ull hash1(string s)
{
int len = s.size();
ull res = 0;
for(int i = 0; i < len; i++)
res = (res * BASE + s[i]) % MOD1;
return res;
}
ull hash2(string s)
{
int len = s.size();
ull res = 0;
for(int i = 0; i < len; i++)
res = (res * BASE + s[i]) % MOD2;
return res;
}
模板(自然溢出法)
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int MAX_N = 10000 + 5;
const int BASE = 131;
ull h[MAX_N];
ull hashs(string s)
{
int len = s.size();
ull res = 0;
for(int i = 0; i < len; i++)
res = res * BASE + s[i];
return res;
}
int main()
{
int n, ans = 0;
cin >> n;
for(int i = 1; i <= n; i++) {
string s;
cin >> s;
h[i] = hashs(s);
}
sort(h + 1, h + n + 1);
for(int i = 1; i <= n; i++)
if(h[i] != h[i - 1])
ans++;
cout << ans << endl;
return 0;
}