散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
我的理解的哈希表就是一种查找数据非常方便的数据结构。
- 哈希表实现方法
开放寻址法:将所有数据放进一个比数据范围大的数组里,每个数据的关键码值是用对特殊值取模得到的。
//拉链法
#include <iostream>
#include <algorithm>
#include <cstring>
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;
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n;
memset(h,-1,sizeof h);
while(n--)
{
string op;
int x;
cin >> op >> x;
if(op == "i") insert(x);
else
{
if(find(x)) puts("Yes");
else puts("No");
}
}
return 0;
}
拉链法:通过一个数组和单链表实现,将数据的key值作为数组下标,在数组的每个位置上连接一个单链表。
//开放寻址法
#include <iostream>
#include <algorithm>
#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;
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n;
memset(h,0x3f,sizeof h);
while(n--)
{
string op;
int x;
cin >> op >> x;
int k = find(x);
if(op == "i") h[k]=x;
else
{
if(h[k]!=null) puts("Yes");
else puts("No");
}
}
return 0;
}
字符串哈希:
字符串哈希是将字符串的前缀通过p进制转换成整型数据存储进哈希表中,可以快速解决字符串的一类问题,就是求一串字符串中的俩段子串相不相等。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010,P = 131;
char str[N];
unsigned long long h[N],p[N];
unsigned long long ha(int l,int r)
{
return h[r] - h[l-1]*p[r-l+1];
}
int main()
{
int n,m;
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n >> m >> str;
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,l2,r1,r2;
cin >> l1 >> r1 >> l2 >> r2;
if(ha(l1,r1) == ha(l2,r2)) cout << "Yes";
else cout << "No";
}
return 0;
}