哈希表存储方式与字符串哈希

哈希表:把值域或者复杂的数据结构映射到0~N,比如说把0~10^9映射到0~10^5上面

实现思路:h(x)=x mod 一个质数,解决多个x的值映射到了同一个h(x)上的冲突

实现方式:拉链法,映射到哪一个数,就在哪个数下面拉一个链表,映射到该数的数都存入链表中

哈希表存储方式与字符串哈希_第1张图片

  1. 添加操作:先求出h(x),然后把它添加到h(x)该槽位下的链表里
  2. 查询操作:遍历链表找到即可
#include

const int N=100003; //取 想要映射到的范围最大值之后的第一个质数

int h[N],e[N],ne[N],idx;

void insert(int x)
{
	int k=(x%N+N)%N;  //实现将x转化为h(x),%N+N是为了解决负数
	e[idx]=x;
	ne[idx]=h[k];
	h[k]=idx++;
}

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

字符串哈希:字符串前缀哈希法

实现思路:把字符串看做是一个p进制的数,然后把它转化为十进制的数后%Q,即映射到0~Q-1

哈希表存储方式与字符串哈希_第2张图片

  1. 字母不能映射为0,从1开始映射
  2. 字符串的哈希假定运气足够好,不存在普通哈希表的冲突问题
  3. p取131或13331,Q取2的64次方(unsigned long long),99.99%不会出现冲突

前缀哈希法:h[i]=h[i-1]*p+str[i]

举例分析:str=“ABCABCDE”,h[0]=0,h[1]="A"的哈希值,h[2]="AB"的哈希值,h[3]="ABC"……

#include

typedef unsigned long long=ULL;

const int N=100010,p=13331;

char str[N];
ULL h[N],p[N];  //数据类型定义为unsigned long long即是将Q设为2^64

int main()
{
	scanf("%s",str+1);
	for(int i=1;i<=n;i++)
	{
        h[i]=h[i-1]*p+str[i]; 
	}
}

计算任何一段子串的哈希值:L~R子串 的哈希值:h[R]-h[L-1]*p^(R-L+1)

       理解:假设h[R]代表“ABCEDA”,h[L-1]代表“ABC”,h[L-1]*p^(R-L+1)即为“ABC[0][0][0]”

       让h[R]-h[L-1]*p^(R-L+1)即为 “EDA”子串的哈希值

#include

typedef unsigned long long=ULL;

const int N=100010,p=13331;

char str[N];
ULL h[N],p[N];

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

int main()
{
	scanf("%s",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];
	}
}

你可能感兴趣的:(数据结构与算法学习历程,数据结构,算法)