快去自定义签名吧~|

张詠然

园龄:3年6个月粉丝:3关注:3

哈希

哈希表

哈希表是将值域比较大但数量比较少的数快速插入与查找的数据结构

哈希表有两种写法,一种是拉链法,一种是开放寻址法

拉链法

拉链法的核心思想是将一个大数取模,如 x mod N

具体做法就是将模完的这个数映射到与它相同的数组下标,并从这一位拉一个单链表

如图:

例题代码如下:

#include <iostream>
#include <cstring>
using namespace std;
const int N = 100003;
int h[N], e[N], ne[N], idx; // 与单链表的定义类似
void insert(int x) // 插入一个元素
{
int t = (x % N + N) % N; // 输入的数有可能是负数,需要加一个N再模N
e[idx] = x;
ne[idx] = h[t];
h[t] = idx;
idx ++ ;
}
bool find(int x) // 寻找x
{
int t = (x % N + N) % N;
for (int i = h[t]; 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);
while (n -- )
{
char op[2];
int x;
scanf("%s%d", op, &x);
if (*op == 'I') insert(x);
else
{
if (find(x)) printf("Yes");
else printf("No");
}
}
return 0;
}

 算法题中一般没有删除操作,如果有,那就将每一个数打上一个标记

开放寻址法

开放寻址法和我们蹲厕所类似,如果经过hash函数之后这个位有元素我们就看下个位置有没有元素

因此数组就需要开的大一点,一般开数据范围的两到三倍

当然也 N 最好也取到一个质数

将拉链法的例题用开放寻址法写代码如下

#include <iostream>
#include <cstring>
using namespace std;
const int N = 200003;
int h[N], null = 0x3f3f3f3f; // null 这个数比10的九次方大
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) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}

字符串哈希

字符串哈希可以实现快速比较两个区间中的元素是否相同

原理是将一个字符串转换成一个p进制数

这里的模 Q 代码中不需要写,因为我们可以用 unsigned long long

以下为字符串哈希的几个注意事项:

  • 字符不能映射成0,否则可能有多个字符串同时映射成0
  • 假设我们的RP足够好,不存在冲突的情况,但我们有一个经验值,P = 131 或 13331(取这两个数基本不会发生冲突),Q = 2^64

例题代码:

#include <iostream>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010, P = 131;
int n, m;
char str[N];
ULL h[N], p[N];
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
scanf("%d%d%s", &n, &m, str + 1); // 从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;
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
if (get(l1, r1) == get(l2, r2)) printf("Yes\n");
else printf("No\n");
}
return 0;
}

 

本文作者:张詠然

本文链接:https://www.cnblogs.com/zyrddd/p/16515785.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   张詠然  阅读(57)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起