哈希表以及我的理解

本文介绍了哈希表的基本概念,包括节省存储空间和减少查询时间复杂度的优势。讨论了整数哈希表的拉链法和开放寻址法,并提供了相关模板。此外,还涉及字符串哈希方法,特别是字符串前缀哈希法及其应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        首先,哈希表的大致作用就是将一个较大值域中的值映射到另一个较小的范围内,这样做最直观的好处就是节省储存空间和减少查询的时间复杂度,鉴于作用对象的不同可以大致分为对整数的“存储结构”和对字符的“字符串哈希方式”。

        我们先讨论整数哈希表,其中所用到的核心方法就是对大值域中的值取模,以此让它们来对应一个新的较小的值,但也因此必然会出现多个值映射到同一个值的情况,为此我们有两种方法来帮助我们梳理储存关系:“拉链法”和“开放寻址法”。

一、拉链法:

基本思想:构造出一条空值单链,也就是要投影的“小范围值域”,我称其为主链,当有重复的只出现时,就令它在接在对应主链位置已有值的旁边,形成一条新的支链,后来的重复值依次接在对应支链后面。

主要模板:

#include<iostream>
using namespace std;
const int N=100003;
int h[N],e[N],ne[N],idx;
memset(h,-1,sizeof h);

拉链法中N的取值标准:大于题目所给“小范围”数据的第一个质数,可以使得取模后对应值重复的情况最少。h为主链位置值,e为当前位置储存值。memset(h,-1,sizeof h)作用为将主链函数h中的值都清空。

向主链插入x值:

int k=(x%N+N)%N;
e[idx]=x;
ne[idx]=h[k];
h[k]=idx++;

k为x要插入的主链位置值,(x%N+N)%N是为使k为正数。原理与单链插入相同。

查询x是否出现过:

int k=(x%N+N)%N;
for(int i=h[k];i!=-1;i=ne[i])
    if(e[i]==x)
        return ture;

return false;

若x出现过,那x一定是在k所在的支链上,因此直接在支链上顺序查找,可以大大减少查找所用的时间。

开放寻址法:

基本思想:开一个数组,在每一个x取模后所在的位置k进行判断,若该处是没有储存过值的空位,或储存的是x的同值,那么就返回k,将x储存于此并得出x的储存位置;如果两种情况都不符合,那就从k开始顺序查找符合的位置,如果到末尾(k==N)也没找到,就再从头(k==0)开始找。

主要模板:

const int N=200003,null=0x33f3f3f;
int h[N];
memset(h,0x3f,sizeof h);

开放寻址法中N的取值标准:大于题目所给“小范围”数据两倍的第一个质数。这里null比10的9次方大,用于规定“空”。

int find(int x)
{
    int k=(x%N+N)%N;
    while(h[k]!=null&&h[k]!=x)
    {
        k++;
        if(k==N) k=0;
    }
    return k;
}

插入x:

cin>>x;
int k=find(x);
h[k]=x;

找到符合条件的位置附于x值。 

查找x:

int k=find(x);
if(h[k]!=null) puts("Yes");
else puts("No");

判断x应当存在的位置是否为空,不是则代表x被储存过。 

---------------------------------------------------------------------------------------------------------------------------------------------

        再看字符串,字符串的哈希方法有“字符串前缀哈希法”,其核心思想就是将字符串中每个字符的哈希值以p进制转10进制的方式转化为数进行储存。

主要模板:

#include<iostream>
using namespace std;
typedef unsigned long long ull;
const int N=100010,P=131;
char str[N];
ull h[N],p[N];

cin>>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];
}

 p作为进制转换所用到的关键值,h[x]表示前x个字符的哈希值。

由此也可以计算字符串中任意一段子链的哈希值:

ull get(int l,int r)
{
    return h[r]-h[l-1]*p[r-l+1];
}

有点难懂,需多加记忆。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值