一、简介
哈希(hash)是很常用的一种数据结构。在STL中,unordered_map和unordered_set的底层实现就是哈希。
哈希值:把任意长度的输入通过哈希变换成固定长度的输出。
1 应用
1.1 加密
由于哈希算法加密快速,但破译很难,几乎不可逆,所以通常被用于加密。
1.2 查找
将一个数组内每一个数都取余一个大质数(已通过严谨的证明,一组数取余质数时,冲突的可能性最小)后,将余数放到对应的数组下标,可以在趋近于 O ( 1 ) O(1) O(1) 的时间内查找数字。
比如,对于一组数: 4 5 9 13 18 20 24,取余17:
但,冲突是一定存在的。如何解决呢?
左右寻址法:在余数下标的左右寻找空位,存放。
链表:将存数字的位置升维(变成链表),往链表上存。
二、运算
对于每个字符串,将它的ASCII码作为128进制转为10进制。举例:
对于abc
a->97 b->98 c->99
哈希值:99+98*128+97*128*128=1601891
程序实现(模998244353):
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define N 100005
const ll mod=998244353;
ll sum;
ll has[N];
string s;
ll qpow(ll a,ll k){
ll ans=1;
while(k){
if(k&1){
ans=ans*a%mod;
}
a=a*a%mod;
k>>=1;
}
return ans;
}
int main(){
getline(cin,s);
has[0]=s[0]%mod;
for(int i=0;i<s.size();i++){
has[i]=(has[i-1]*128+s[i])%mod;
}
cout<<has[s.size()-1];
return 0;
}
三、实践
查字典
1.1 题目描述
先输入n行,每行两个单词,分别为本国单词和外国单词。再输入m行,每行一个外国单词。输出m行,为输入时外国单词对应的本国单词。
1.2 思路
本质时一道map模板题,但我们学了哈希,所以尝试用哈希来做。
输入时,将每一个外国单词的哈希值存到一个数组里。在询问时,将询问的单词也转换为哈希,遍历刚才存所有外国单词的数组。若有相同的哈希值,则找到了。
1.3 代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
#define N 1005
const ll mod=998244353;
ll n,m;
string s,has[N];
ll c[N];
ll qpow(ll a,ll k){
ll ans=1;
while(k){
if(k&1){
ans=ans*a;
}
a=a*a;
k>>=1;
}
return ans;
}
ll ha(string x){
ll sum=0;
for(int i=0;i<x.size();i++){
sum+=pow(128,(x.size()-1-i))*(ll)x[i];
}
return sum;
}
string y;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>has[i]>>y;
c[i]=ha(y);
}
cin>>m;
for(int i=1;i<=m;i++){
string x;
cin>>x;
ll h=ha(x);
bool flag=0;
for(int j=1;j<=n;j++){
if(c[j]==h){
cout<<has[j];
flag=1;break;
}
}
if(flag==0){
cout<<"eh";
}
pr;
}
return 0;
}