基础算法——哈希表
本文主要内容:
- 基础复习
- 拉链法
- 蹲坑法(开放寻址法)
1 基础复习
- 主要功能:
- 模拟set,往集合中插入一个数字,查询这个数字是否在集合中出现过
模板题1: Acwing840. 模拟散列表
方法1:拉链法
- 思路:
- 用一个邻接表来存储集合中所有数。
- 插入时对于每一个数x计算其mod N的余数k作为表头,将其插入邻接表表头位置(头插法)
- 查询时同样计算出k,然后遍历h[k]这条链,存在x返回true,否则返回false
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 5;
int idx, h[N], e[N], ne[N];
int n;
void add(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()
{
memset(h, -1, sizeof h);
cin >> n;
while(n--)
{
char op;
int x;
cin >> op >> x;
if(op == 'I')add(x);
else
{
if(find(x))cout << "Yes";
else cout << "No";
cout << endl;
}
}
return 0;
}
方法二:蹲坑法
- 思路:
- 用一个一维数组hash[]来存储所有数
- 插入x时同样计算出k,然后从k出往后找,找到一个没有被其他元素占用的位置(为空或为x),然后把x放到这个坑里
- 查询x时同样计算出k,然后从k处往后找到一个没有被其他元素占用的位置并返回该位置,若该位置元素为x则true,为空则false
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 5;
int h[N * 3];
int find(int x)
{
int k = (x % N + N) % N;
while(h[k] != x && h[k] != 0x3f3f3f3f)
{
k++;
if(k == 3 * N - 1)
k = 0;
}
return k;
}
int main()
{
memset(h, 0x3f, sizeof h);
int n;
cin >> n;
while(n--)
{
char op;
int x;
cin >> op >> x;
int px = find(x);
if(op == 'I')
h[px] = x;
else
{
if(h[px] == 0x3f3f3f3f)cout << "No";
else cout << "Yes";
cout << endl;
}
}
}
模板题2: Acwing841. 字符串哈希
思路:将字符串映射成一个P进制数
#include<iostream>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e5 + 5, P = 131; //不容易重复
ULL h[N], p[N];
int n, m;
char str[N];
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
cin >> n >> m;
cin >> 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;
cin >> l1 >> r1 >> l2 >> r2;
if(get(l1, r1) == get(l2, r2))cout << "Yes";
else cout << "No";
cout << endl;
}
}
2 STL unordered_map实现哈希表
例题:Acwing1523. 学生课程列表
- 时间复杂度:
o(n2logn)- 思路:
- 将名字与vector数组映射,每个名字对应的vector数组存储课程编号
#include<iostream>
#include<vector>
#include<algorithm>
#include<unordered_map>
using namespace std;
unordered_map<string, vector<int>>ha;
int n, k;
int main()
{
cin >> n >> k;
while(k--)
{
int id, ni;
cin >> id >> ni;
while(ni--)
{
string x;
cin >> x;
ha[x].push_back(id);
}
}
while(n--)
{
string x;
cin >> x;
sort(ha[x].begin(), ha[x].end());
cout << x << ' ' << ha[x].size() << ' ';
for(int i = 0; i < ha[x].size(); i++)
printf("%d ", ha[x][i]);
puts("");
}
return 0;
}