Hash函数

今天学习一下Hash函数:Hash表我以前不会实现,只能用c++STL中的map实现,然鹅map对于字符串的部分处理不如字符串hash方便。
Hash实际上是离散化的映射
使用链式前向星建表:
head[x]:表头数组,起index作用
edge[x]:存储该边的值,如在图论中存储边权值



int ver[2*maxn],edge[2*maxn],next[2*maxn],head[2*maxn];//一般为无向图需要存两次
void add(int x,int y,int z){
ver[++tot]=y, edge[tot]=z;
next[tot]=head[x], head[x]=tot;
}

链式前向星的储存就类似于链表,可以通过表头数组定位每组数据
链式前向星的查询:

for(int i=head(x);i;i=next[i]){//遍历x的子边们
int y=ver[i],z=edge[i];//取出来(x,y)这条边,权值为z;
}

无向图存两次,(x,y),(y,x);若初始化tot=1,tot从偶数2开始存储(x,y)与(y,x);x xor 1=x+1;**(详情请见位运算一节)**所以ver[i],ver[i xor 1]为一边的起点与终点;
学会了前向星的基础操作后,就可以来搞Hash了
Hash表两个基本操作:
1.计算Hash函数的值(定义hash(x),将x全部映射到hash(x))
2.定位到对应链表中遍历,比较。
eg.H(x1,x2...x3)=f(x1,x2...x3)mod p

https://www.acwing.com/problem/content/139/

有N片雪花,每片雪花由六个角组成,每个角都有长度。

第i片雪花六个角的长度从某个角开始顺时针依次记为ai,1,ai,2,…,ai,6。

因为雪花的形状是封闭的环形,所以从任何一个角开始顺时针或逆时针往后记录长度,得到的六元组都代表形状相同的雪花。

我们称两片雪花形状相同,当且仅当它们各自从某一角开始顺时针或逆时针记录长度,能得到两个相同的六元组。

求这N片雪花中是否存在两片形状相同的雪花。

输入格式
第一行输入一个整数N,代表雪花的数量。

接下来N行,每行描述一片雪花。

每行包含6个整数,分别代表雪花的六个角的长度(这六个数即为从雪花的随机一个角顺时针或逆时针记录长度得到)。

同行数值之间,用空格隔开。

输出格式
如果不存在两片形状相同的雪花,则输出:

No two snowflakes are alike.
如果存在两片形状相同的雪花,则输出:

Twin snowflakes found.

两片相同的雪花,六个角的长度乘积和长度和都相同,因此我们可以定义
hash(\(a_{i,1},a_{i,2}...a_{i,6}\))=\((\sum_{j=1}^{6}a_{i,j}+\prod_{j=1}^{6}a_{i,j})\)%p
然后建个hash表插入雪花数据,检查一下即可

#include<bits/stdc++.h>
using namespace std;
const int size=100010;
int H(int *a)
int main( ){
}

字符串hash
取两个数p,m;把字符串看为p进制数,hash(string)=string(p)mod m
小概率发生hash碰撞,取p=131/13331时碰撞概率低
通常取unsigned long long m=264, 产生溢出后等效于对264 取模
一般会处理字符串的前缀哈希(预处理前缀哈希复杂度o(N),查询字串哈希复杂度O(1))
string s->H(s)
string s+t->H(s+t)
H(t)=( H(s+t) - H(s) * p ^ length(t) ) mod m;
eg:

string x="abc";string c="d";
//s的p进制数表示:1 2 3
H(s)=1*p^2+2*p+3
H(s+c)=1*p^3+2*p^2+3*p+4=H(s)*p+H(c);

https://www.acwing.com/problem/content/140/
https://www.acwing.com/problem/content/141/
(可用Manacher算法)
https://www.acwing.com/problem/content/142/

// 1.今天被zsy小姐姐搞烦了,把hash的题解咕掉吧~咕咕咕
// 2.学了点hash终于可以学一些字符串算法了,今早在看kmp,确实感觉会好一点

posted @ 2022-03-09 23:37  misasteria  阅读(119)  评论(0编辑  收藏  举报