Hash(学习笔记)

写这篇博客仅是为了凑齐神龙,真想学Hash请另寻高明.

关于哈希Hash,我没有找到什么专门学习它的博客.因为它实在是不太好讲,但实现起来其实是很容易的,它的思想很简单,可是就是不太好阐释,而且它就像离散化一样,一般情况下都用于对数据的预处理.

反正我对Hash的理解就是,当碰到一些很难处理的数据时(比如字符串、很大的数等等),可以考虑将它通过哈希函数变成一个较小的常数,这个较小的常数就称作哈希值.

真的不想再用文字来叙述这个东西了

字符串哈希:(最常用,最重要)

给出两个仅含大写字母的字符串s1,s2,求s1在s2中出现了多少次.

unsigned long long power[MAXN],sum[MAXN];
//unsigned long long
char s1[MAXN],s2[MAXN];
int main(){
    power[0]=1;
    for(int i=1;i<=MAXN;i++)
		power[i]=power[i-1]*b;
//预处理出b^n,b是一个质数(自行赋值).
    scanf("%s%s",s1+1,s2+1);
    	int n=strlen(s1+1),m=strlen(s2+1);
    for(int i=1;i<=m;i++)
		sum[i]=sum[i-1]*b+s2[i]-'A'+1;
//计算主串s2的哈希值
//这是字符串哈希的精髓,好好理解一下
    unsigned long long s=0;
    for(int i=1;i<=n;i++)
		s=s*b+s1[i]-'A'+1;
//计算匹配串s1的哈希值
//因为我们要计算的是s1在s2中出现的次数,所以是要拿s1
//整个串的哈希值和s2的部分串的哈希值比较,看是否相等
//这就是为什么本题中s1的哈希值直接用变量s存,而s2的
//哈希值要存在一个数组中
//此外,s1和s2的哈希函数(即哈希值的计算方法)要相同.
    int ans=0;
    for(int i=0;i<=m-n;i++)
		if(s==sum[i+n]-sum[i]*power[n])
        	ans++;
//枚举s2的长度等于s1的子串的哈希值,如果相等,ans+1
    printf("%d
",ans);
    return 0;
}

哈希表:(真心觉得用得不多)

(该图是在模16意义下的哈希表):

【模板】字符串哈希

题意:给你n个字符串,判断其中不相同的字符串的个数.

分析:做法很多,我下面的代码是将字符串哈希和哈希表的思想结合起来做的.应该会更有助于全面理解哈希.

#include<bits/stdc++.h>
using namespace std;

const int p1=47,p2=79,mod1=1e6+3,mod2=1e6+9;
//构造两个哈希函数,只有同时满足两个哈希值相等
//才是相同的字符串,能有效降低哈希冲突的概率.
int n,tot,ans;
int nxt[10005],end[10005],head[mod1+5];
string s[10005];

void insert(int x,int y){
    nxt[++tot]=head[x];
    head[x]=tot;
    end[tot]=y;
}
//将一个字符串通过两个哈希函数得到的两个哈希值
//插入邻接表(哈希表)
//结合上面那个图来看就是把x当做表头
//y当做表头后链表上的值

int query(int x,int y){
    for(int i=head[x];i;i=nxt[i]){
        if(end[i]==y) return 1;
    }
    return 0;
}
//到哈希表中查询字符串是否存在过

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>s[i];
        int len=s[i].size();
        int sum1=0,sum2=0;
        for(int j=0;j<len;j++){
            sum1=(sum1*p1+s[i][j])%mod1;
            sum2=(sum2*p2+s[i][j])%mod2;
        }
//双哈希函数,这里没有让s[i][j]-'a'什么的,
//是因为字符串可能小写,可能大写,可能是数字,
//就干脆让它自己强制转换成数字就好了.
        if(query(sum1,sum2)==1) ans++;
        else insert(sum1,sum2);
    }
    printf("%d",n-ans);
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10333536.html