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

一、哈希表

第二章数据结构(三)(哈希表、stl)_第1张图片

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

#include
//哈希
//模数一般取质数,距离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
//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进制的结果。然后进行哈希

第二章数据结构(三)(哈希表、stl)_第2张图片

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

(2)不存在冲突的条件

第二章数据结构(三)(哈希表、stl)_第3张图片

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

(4)

#include
//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");
  }
}

你可能感兴趣的:(蓝桥准备,数据结构,散列表,哈希算法)