Hash表
hash表
- hash表
- 存储方式
- 开放寻址法
- 拉链法
- 字符串hash
离散化实际上就是一种特殊的哈希方式【单调递增】
拉链法
如果有一个数是冲突的,用一条链将他们栓起来,像邻接表一样
void insert(int x)
{
int k =((x % N) + N) % N;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx ++;
}
插入数,h
存头节点,e
存真实际值
e[idx] = x;
存值
ne[idx] = h[k];
将next
指针指向下一行
h[k] = idx ++;
让h[k]
指向上一行
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;
}
查找数,图·的遍历方式差不多
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
const int N = 100003;
int n,h[N],ne[N],e[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()
{
cin >> n;
memset(h,-1,sizeof h);
while(n--)
{
char op[2];
int x;
scanf("%s%d",op,&x);
if(op[0]=='I')insert(x);
else if(find(x))puts("Yes");
else puts("No");
}
}
开放寻址法
N = 200003;
注意
开放寻址法一般要开到题目数据2~3倍以上
while(h[k]!=Null &&h [k]!=x)
{
k++;
if(k == N) k = 0;
}
h[k]!=Null &&h [k]!=x
当前位置是空就往后走
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
const int N = 200003,Null = 0x3f3f3f3f;
int n,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()
{
cin >> n;
memset(h,0x3f,sizeof h);
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("Yes");
else puts("No");
}
}
return 0;
}
字符串前缀哈希法
如
\(str = "abcdhhj"\)
\(h_1 = "a"\)
\(h_2 = "ab"\)
\(....\)
\(h_7 ="abcdhhj"\)
特别的 \(h_0 =0\)
注意:\(h\)存的是\(str\)的哈希值
\(A B C D\)
A | B | C | D |
---|---|---|---|
1 | 2 | 3 | 4 |
可看成\(P\)进制下的
\(1 \times p^3 +2\times p^2 +3\times p +4\times p^0\)
\((1 \times p^3 +2\times p^2 +3\times p +4\times p^0)modQ\)
将任何一个数映射到[0,Q-1]
内
一般情况下不能将字母映射成\(0\)
如 AA
和A
假定\(R_p\)足够好完全不考虑冲突,当 \(p= 131\)或\(p=13331\),\(Q=2^{64}\)
\(99.99\)%的情况下不会出现冲突
unsigned long long
存储hash值
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
const int N = 1000010,P=131;
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()
{
int n,m;
scanf("%d%d%s",&n,&m,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;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else puts("No");
}
return 0;
}
“风雪越是呼啸,雪莲越是绽放”