第六课:哈希表,STL

一、哈希表

哈希表是将大范围数据映射到小范围的存储方式。映射需要设定一个哈希函数。有常规数字哈希以及字符串哈希。

1.数字哈希

数字哈希的哈希函数是(x%N+N)%N,并且要去N是质数,以减少冲突的情况。对于整数就就是直接模N,但是考虑让负数模N和整数的值一样,需要改成这个样子。

映射后,可能有多个数字被映射成相同的k值,那么需要处理冲突。常见方法有开放寻址法和拉链法。

(1)拉链法

拉链法顾名思义,在每个k值上拉出一条链表,由链表存储映射到这个k值上的x值。

 

#include<iostream>
#include<cstring>
using namespace std;

const int N =100003;
int h[N],e[N],ne[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()
{
    int n; cin>>n;
    memset(h,-1,sizeof h);//全部设为1  在cstring里面
    while(n--)
    {
        string op;
        cin>>op;
        int x;
        cin>>x;
        if(op=="I") insert(x);
        else 
        {
            if(find(x))  cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }
    }
    return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3449879/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

(2)开放寻址法

 找到x需要存储的k值,如果k已被占用,就存储到k+1,如果仍被占用,就继续往下走,直到x被存储。为此需要一个null标记是否为空。开的数组需要时数据的2~3倍。

#include<iostream>
#include<cstring>
using namespace std;

const int N =200003;
int h[N],null=0x3f3f3f3f;



int  find(int x)//返回x应该插入的位置
{
    int t=(x %N + N) % N;
    while(h[t]!=null&&h[t]!=x)//有元素且不是x
    {
        t++; if(t==N)  t=0;
    }
    return t;
}


int main()
{
    int n; cin>>n;
    memset(h,0x3f,sizeof h);//全部设为1  在cstring里面
    while(n--)
    {
        string op;
        cin>>op;
        int x;
        cin>>x;
        int k=find(x);
        if(op=="I") h[k]=x;
        else 
        {
             if(h[k]==null)cout<<"No"<<endl;//x应该插入的位置没有值
             else cout<<"Yes"<<endl;

        }
    }
    return 0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3449879/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.字符串哈希

字符串前缀哈希,将1~n的字符串映射为一个p进制数(最后对Q取模)。h存储的是前n个字符的哈希值。

 注意不能映射为0(方便起见数组从1开始存储),这样就会引起冲突。根据经验公式,P=131或者133331,Q=2^64时,基本不会冲突。

 没一个字符串的哈希值是固定的,当我们需要计算某个子串的哈希值时,方法如图。

因此判断两个字符串是否相等,比较哈希值即可。

哈希值数组构造方式易知为 

 

//这里填你的代码^^
#include<iostream>
using namespace std;

const int N =100010,P=131;

typedef unsigned long long  ULL;

int h[N],p[N];//p数组预处理p的n次方(p[n]=p^n)
char str[N];
int n,m;

ULL gethash(int l,int r)
{
    return h[r]-h[l-1]*p[r-l+1];//计算公式
}
int main()
{
    cin>>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;
        cin>>l1>>r1>>l2>>r2;
        if(gethash(l1,r1)==gethash(l2,r2))  cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }

}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3451665/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值