哈希表的存储及定位方式有开放寻址法和拉链法,所谓开放寻址法。对于使用哈希表来讲最重要的是哈希函数的构造,一般来讲哈希的作用就是将范围比较大但是比较稀疏的数据映射到小范围的数据里面,而哈希函数就是实现此功能的函数,一般的做法是对每一个数据模上一个比较小的数n(n一般取10的5次方到10的6次方,注意,n要是一个质数),这样最终的范围就会在0到n之间。那么这时就会出现一个问题,就是万一有两个数同时对n取模结果相同怎么办,这是一个无法避免的问题,这时的解决方法就有两种,一种就是开放寻址法,当我将x映射到k之后,加入k的位置已经有数据了,那么就向后找一个,直到找到位置,如果k达到了n怎么办呢,这是就是k从0开始,这种方法一般要将数组大小开到n的两到3倍,至于怎么判断第k个位置有无数据呢,可以在初数组的每一个位置存放0x3f3f3f3f,每当可以在某位置存放x时,就将值改为x,为什么是0x3f3f3f3f呢,因为这是一个在计算机内近似无穷大的数,会在待映射的数据之外,处理方便,不会遇到和它相等的值。接下来看一下开放寻址法的代码
#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;
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;
}
第二种方法是拉链法,拉链法就是在映射数组的每个位置下面挂一条单链表,每当遇到一个映射到某个位置的数,就把它插入下方的链表,每次寻找的时候按链表遍历即可,下面看一下拉链法的代码
#include<iostream>
#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;
cin >> n;
memset(h, -1, sizeof h);
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;
}