先简述一下思路:
第一个是拉链法,用邻接表形式处理冲突
第二个是开放寻址法
拉链法
我们先来看插入和查询的操作:
插入操作:
我们先来建一个模拟链表, e[N], ne[N]。//之后会写一起模拟单链表,双链表
还有一个数组:h[N];
还有一个类似于指针的idx;
注意:这里取模一般N要选取质数,这样冲突最小。
void insert(int x) {
int u = (x % N + N) % N;//c++中取模可能有负数,这样避免出现
e[idx] = x;
ne[idx] = h[u];//这里相当于头插
h[u] = idx++;
}
然后就是查询操作:
bool query(int x) {
int u = (x % N + N) % N;
for (int i = h[u]; i != -1; i = ne[i]) {
if (e[i] == x) {
return true;
}
}
return false;
}
就是遍历一遍h【u】对应的链表:
有了上述操作:
原题链接:模拟散列表
#include <iostream>
#include <cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int h[N], e[N], ne[N],idx;
void insert(int x) {
int u = (x % N + N) % N;
e[idx] = x;
ne[idx] = h[u];//这里相当于头插
h[u] = idx++;
}
bool query(int x) {
int u = (x % N + N) % N;
for (int i = h[u]; i != -1; i = ne[i]) {
if (e[i] == x) {
return true;
}
}
return false;
}
int main()
{
int n;
scanf("%d", &n);
memset(h,-1,sizeof(h));
char op[2];
int x;
while (n--) {
scanf("%s%d", op,&x);
if (*op == 'I') {
insert(x);
}
else
{
if (query(x)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
开放寻址法
这里插入和查询只需要一个find函数
但是要求h的数组长度至少要为原数组的2,3倍
int find(int x) {
int u = (x % N + N) % N;
while(h[u]!=null&&h[u]!=x) {
u++;
if (u == N) u=0;
}
return u;
}
插入:返回空位
查询:
if (h[find(x)] == null) puts("No");
else puts("Yes");
源代码:
#include <cstring>
#include <iostream>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f;
int h[N];
int find(int x)
{
int t = (x % N + N) % N;
while (h[t] != null && h[t] != x)
{
t ++ ;
if (t == N) t = 0;
}
return t;
}
int main()
{
memset(h, 0x3f, sizeof h);
int n;
scanf("%d", &n);
while (n -- )
{
char op[2];
int x;
scanf("%s%d", op, &x);
if (*op == 'I') h[find(x)] = x;
else
{
if (h[find(x)] == null) puts("No");
else puts("Yes");
}
}
return 0;
}