哈希hash 各种用法最全详解
哈希hash
什么是哈希
- 哈希表是一种散列表,可支持插入元素和查询元素的操作。
- 当元素的取值范围特别大时,布尔数组的下标无法支持,这时可以用到哈希表。
操作
- 对于一个哈希表,需要取一个固定的模数 p p p,哈希表的下标可以开到 p p p的 1 − 2 1-2 1−2倍大,
- 具体怎么用请往下看:
插入元素
- 例如有如下元素 18 , 9 , 13 , 5 , 31 18,9,13,5,31 18,9,13,5,31,要把它们存入一个哈希表中,
- 当前 p = 13 p=13 p=13
- 放入 18 18 18,对 p p p取余,得到 5 5 5,那么就在 h a s h [ 5 ] = 18 hash[5]=18 hash[5]=18;
- 放入 9 9 9,对 p p p取余,得到 9 9 9,那么就在 h a s h [ 9 ] = 9 hash[9]=9 hash[9]=9;
- 放入 13 13 13,对 p p p取余,得到 0 0 0,那么就在 h a s h [ 0 ] = 13 hash[0]=13 hash[0]=13;
- 放入 5 5 5,对 p p p取余,得到 5 5 5,但 h a s h [ 5 ] hash[5] hash[5]有值了,那么下标右移,直到有空位为止, h a s h [ 6 ] = 5 hash[6]=5 hash[6]=5;
- 放入 31 31 31,对 p p p取余,得到 5 5 5,但 h a s h [ 5 ] hash[5] hash[5]有值了,那么下标右移,直到有空位为止( h a s h [ 6 ] hash[6] hash[6]也有值了), h a s h [ 7 ] = 18 hash[7]=18 hash[7]=18。
void insert(int t)
{
int x=t%p;
while(hash[x])
{
x++;
x%=maxn;//如果到了哈希表末尾那么就移动到开头
}
hash[x]=t;
}
查询元素
- 若上面的元素插入完后,又有一些元素,我们需要判断它们是否在表中存在,
- 如 2 , 31 , 5 , 6 2,31,5,6 2,31,5,6:
- 查询 2 2 2,对 p p p取余,得到 2 2 2, h a s h [ 2 ] = 0 hash[2]=0 hash[2]=0,那么说明不存在;
- 查询 31 31 31,对 p p p取余,得到 5 5 5, h a s h [ 5 ] = 18 hash[5]=18 hash[5]=18,但不能说明不存在,要一直右移,每一位都判断一次,直到到了一个空位, h a s h [ 6 ] = 5 hash[6]=5 hash[6]=5, h a s h [ 7 ] = 31 hash[7]=31 hash[7]=31,发现存在,退出;
- 查询 5 5 5,对 p p p取余,得到 5 5 5, h a s h [ 5 ] = 18 hash[5]=18 hash[5]=18, h a s h [ 6 ] = 5 hash[6]=5 hash[6]=5,发现存在,退出;
- 查询 6 6 6,对 p p p取余,得到 6 6 6, h a s h [ 6 ] = 5 hash[6]=5 hash[6]=5, h a s h [ 7 ] = 31 hash[7]=31 hash[7]=31,直到 h a s h [ 8 ] = 0 hash[8]=0 hash[8]=0,没有发现存在,退出。
int find(int t)
{
int x=t%p;
while(hash[x])
{
if(hash[x]==t) return 1;
x++;
x%=maxn;
}
return 0;
}
- 这样也挖掘出了哈希的一个新功能——判重!!!
插入与判重
- 可以把两个合并,
- 使它可以做到:如果返回是否存在,若不存在就插入!
int check(int t)
{
int x=t%p;
while(hash[x])
{
if(hash[x]==t) return 1;
x++;
x%=maxn;
}
hash[x]=t;
return 0;
}
压缩
- 如果要存入的不是一个数,而是一个数对,甚至一个字符串呢?
- 当然可以,这时需要把各种千奇百怪的东西都压缩成一个数(归根结底还是变成了一个数)
- 怎么压缩?
- 尽可能使出现重复的概率少,
- 如数对 ( 4 , 3 ) (4,3) (4,3),
- 一种可以直接相乘,压缩成 12 12 12,但 ( 2 , 6 ) (2,6) (2,6)也是 12 12 12,会有重复,在哈希表里会耗更多时间;
- 一种可以采用某种进制,若数对 ( x , y ) (x,y) (x,y)满足 x , y ∈ [ 0 , 9 ] x,y\in[0,9] x,y∈[0,9]那么可以压缩成 4 ∗ 10 + 3 = 43 4*10+3=43 4∗10+3=43,而且能压缩成 43 43 43的只有数对 ( 4 , 3 ) (4,3) (4,3),减少重复,效率就会增加。
- 那么字符串若全是小写字母,则可以压缩成 27 27 27进制。
应用
记忆化搜索
- 在搜索若想实现记忆化,但空间会爆炸的话,那么就可以用哈希!
- 哈希表中每一位不仅存下压缩后的状态,还要存下对应的搜索出来的值。
- 若不用哈希的搜索是这样的:
int dfs(int x,int y)
{
if(x==1&&y==1) return 1;
else
{
int s=0;
for(int i=1;i<x;i++) s+=dfs(i,y-1);
return s;
}
}
- 用了哈希实现记忆化就是这样的:
int check(int i,int y)
{
int x=i*y%p;
while(hash[x].use)
{
if(hash[x].i==i&&hash[x].y==y)
{
return x;
}
}
return -x;//如果是负数代表没有找到!
}
void dfs(int x,int y)
{
if(x==1&&y==1) return 1;
else
{
int s=0;
for(int i=1;i<x;i++)
{
int bz=check(i,y-1);
if(bz>0) s+=hash[bz].ans;
else
{
int t=dfs(i,y-1);
s+=t;
bz=-bz;//取相反数变回原来的下标
hash[bz].ans=t;
hash[bz].i=i;
hash[bz].y=y;
}
}
}
}
哈哈哈哈哈哈哈哈哈哈

浙公网安备 33010602011771号