哈希表的运用

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表的时间复杂度都是O(1).基本用到哈希表的都是O(n).

如:维护一个集合,支持如下几种操作:

I x,插入一个数 x; Q x,询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果。

插入一个数或者询问当前数在集合是否出现过可以使用哈希表的开放寻址法和拉链法。
题目入口:模拟散列表
哈希表的开放寻址法的做法,当查找一个数

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int null=0x3f3f3f3f;
const int N=200003;
int h[N];
int finnd(int x) //开放寻址法的查找
{    x=(x%N+N)%N;   //这里因为可能出现负数的情况所以先模之后加上N在取模
    while(h[x]!=null&&h[x]!=x) //开放寻址法查找如果当前这个位置不为空并且不是要查的数就一直向后查询,直到为空表示不存在这个数
    {
        x++;
        if(x==N)//如果查到最后一个数,直接定位到第一个数
            x=0;
    }
    return x;  //返回查询数的地址
}
int main()
{ char ch;
    int x;
    int flag;
    char op[2];  //字符用数组来安全读取

    int n;
scanf("%d",&n);
memset(h,0x3f,sizeof(h));  //memset是一个字节一个字节来读取
    while(n--)
    {
       scanf("%s%d",op,&x);  //这里用字符串来读取字符可以将空白字符吸收掉,防止因为数据出现的WA
        flag=finnd(x);  //查询x这个数
        if(*op=='I')  //如果是插入操作就直接插入进数组中
            h[flag]=x;
        else
        {
            if(h[flag]==null)   //如果是查找当前这个数查不到为空的话就表示不存在这个数
                printf("No\n");
            else
                printf("Yes\n"); }
    }
}

字符串的哈希:主要是以O(1)的复杂度来判断两个子字符串是否相等。

例如:aabbaabb
下标从1开始:l=1 r=3的aab 和l=5 r=7aab相等,那怎么使用哈希表来判断呢?
在这里用一个无符号长整形数组h[i]来表示前i个字符的映射值,当然溢出也不需要去考虑,如果是aab相当于a×a+b,如果是abb,就是a*a+b这样来表示映射值。
这里用str数组来保存原字符串,而且还需要用一个base来统一字符串的模,base这里有两个经验值,131 和13331,这样可以在很大程度上减少冲突。
那么h[i]的递推式为:h[i]=h[i-1]*base+str[i];
这里如果我们需要知道两个子字符串是否相等,可以求出每一段映射值的大小然后进行比较,这样如果映射值相等的话在很大概率上着两个子字符串就表示相等。
如果我们需要求【3,6】的映射值怎么求呢
假如给定一个数字字符串 :1 2 3 4 5 6
其实我们可以用h[6]-h[2] ×base的4次方。
因为h[6]的值为123456,而h[2]的值为12,可以用123456-120000=3456即为 【3,6】的值。
所以我们在这里引进一个位权数组 p[],表示当前i的权值为多少。

所以最终我们求L->R 可以=h[R]-h[L]×P[R-L+1]。
hash表的使用: hash表的运用

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
typedef unsigned long long ull;
const int N=1000010,base=131;
int h[N],p[N];
int m;
char str[N];
bool get(int a,int b,int c,int d)
{
    int x=h[b]-h[a-1]*p[b-a+1];  //取[a,b]的hash值
    int y=h[d]-h[c-1]*p[d-c+1];     //取[c,d]的hash值
    return x==y;
}
int main()
{    p[0]=1;  //先将权的第一值赋值为1
    scanf("%s%d",str+1,&m);
    int a,b,c,d;
    int len=strlen(str+1);
    for(int i=1;i<=len;i++)
    {
        p[i]=p[i-1]*base;   //计算第i个数的权值
        h[i]=h[i-1]*base+str[i];  //计算第i个数的hash值
    }
      while(m--)
      {
          scanf("%d%d%d%d",&a,&b,&c,&d);
           if(get(a,b,c,d))  //判断[a,b]和[c,d]是否相等
           printf("Yes\n");
           else printf("No\n");
           
      }
      
    
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值