第二章数据结构(三)(哈希表、stl)

本文介绍了三种在C++中实现哈希表的方法:拉链法通过单链表解决哈希冲突,开放寻址法则使用数组并动态寻找空位置,以及字符串哈希中的前缀哈希避免映射冲突。展示了如何通过这些方法进行插入、查找和子串比较操作。
摘要由CSDN通过智能技术生成

一、哈希表

1、拉链法 (加一个单链表)

#include<bits/stdc++.h>
//哈希
//模数一般取质数,距离2的整数次幂尽量远
//拉链法有多个槽,每个槽连接一个单链表
using namespace std;
const int N=1e5+3;
int h[N],e[N],ne[N],idx=0;
//h数组为每一个槽的头结点,和ne性质一样都是存的下一个结点的下标
//e存每一个结点的数值
//ne存某个idx结点的下一个结点
void insert(int x)
{
    int k=(x%N+N)%N;//C++负数取模余负数
    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])//i是下标
    {
        if(e[i]==x)
            return true;
    }
    return false;
}
int main()
{
    int n,x;
    cin>>n;
    memset(h,-1,sizeof(h));//一开始所有的槽都是空的
    while(n--)
    {
        char op[2];
        cin>>op>>x;
        if(*op=='I')insert(x);
        else
        {
            if(find(x))puts("Yes");
            else puts("No");
        }

    }
}

2、开放寻址法 (数组长度是题目数据个数的2~3倍)没有位置向后找

#include<bits/stdc++.h>
//840 开放寻址法模拟散列表
using namespace std;
const int N=2e5+3,null=0x3f3f3f3f;//取一个无穷大的数
int h[N];
//x在表中存在的话返回位置,没有就返回应该在这个位置
//也就是一定会找到一个位置(在表没有满的情况下)
int find(int x)
{
    int k=(x%N+N)%N;
    //下面是一个巧妙的循环
    //如果x在哈希表中一定会在找到一个空位置前找到。
    //所以开放寻址法不支持通过设置null值的方法来删除数
    while(h[k]!=null&&h[k]!=x)
    {
        k++;
        if(k==N)k=0;//再从头去找
    }
    return k;
}
int main()
{
    int n;
    memset(h,0x3f,sizeof(h));//memset按照字节来赋值
//为-1的时候,四个字节合起来还是-1,为0,四个合起来都是0;
    cin>>n;
    while(n--)
    {
        char op[2];
        int x;
        cin>>op>>x;
       // scanf("%s%d",op,&x);
        int k=find(x);
        if(*op=='I') h[k]=x;
        else
        {
            if(h[k]!=null) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

3、字符串哈希(字符串前缀哈希法)

可以利用前缀哈希计算出所有子串的哈希

字符串前缀哈希:将字符串当做一个p进制的数字,计算得到10进制的结果。然后进行哈希

(1)不能映射为0,因为多个0组合到一起还是0,导致多个不同的字符串映射到同一个位置。

(2)不存在冲突的条件

(3)字符串哈希求出所有前缀和的哈希求子串的哈希的计算公式:

(4)

#include<bits/stdc++.h>
//841 判断某两个子串是否相同
using namespace std;
typedef unsigned long long int ULL;
const int N=2e5+10,P=131;
int n,m;
char str[N];//存储字符串
ULL h[N],p[N];//p用于方便存p的几次方h用于保存某一个前缀的哈希值
ULL get(int l ,int r)
{
    return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
  //注意从str的第一位开始存储的方法
  scanf("%d%d%s",&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;
      scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
      if(get(l1,r1)==get(l2,r2))puts("Yes");
      else puts("No");
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值