哈希表及字符哈希

本文详细介绍了哈希表的概念,包括如何通过key-value形式存储数据,以及当key范围较大时如何通过取模操作进行索引。针对哈希冲突,文章提到了开放寻址法和拉链法两种解决策略,并提供了相应的代码示例。此外,还探讨了字符串哈希在字符串匹配中的应用,讲解了哈希值的计算方法以及区间哈希值的求法,强调了哈希值在保证不同字符串区分度上的重要性。

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

一、 定义

  1. 哈希表是又称散列表,一种以 “key-value” 形式存储数据的数据结构(h[key] = value)。输入查找的值 key,就可以快速地找到其对应的 value。
  2. 可以把哈希表理解为一种高级的数组,这种数组的下标可以是很大的整数,浮点数,字符串甚至结构体。

但如果key值很大超出下标范围,这时就体现了哈希的作用,也就是key值的使用。

二、key值的使用

  1. 当 key 的范围比较小的时候,可以直接把 key 作为数组的下标。
  2. 当 key 的范围比较大,比如以 10^9范围内的整数作为 key 的时候,就需要用到哈希表。一般把 key 模一个较大的质数(M)作为索引(key = key % M)。
  3. 当 key 为字符串的情况,一般不直接把字符串作为 key,而是先算出字符串的哈希值,再把其哈希值作为 key 插入到哈希表里。

如果两个不同的值模完后的值是相同的这时就产生了一个关键性的现象,冲突。

解决冲突最长用的两种方法:开放寻址法,拉链法。

开放寻址法

思路

value值摸完以后的key值(key = value % M)作为数组h下标,如果此时数组h[key]不为空,我们就让key向后移一位,直至数组h[key]为空时,将value加入。

代码实现:

int find(int v)
{
	int k = (v % N + N) % N; // 加N的目的是为了让负数v变为正数
	while (h[k] != INF && h[k] != v) //INF为大于v范围的数
	{					//哈希表例没有重复的value,每一个value都有唯一的key与之对应
		k++; // 不为空,不重复,往后移
		if (k == N) k = 0; //到尾在从头找
	}
	return k;	// 不存在v返回INF的位置(为了value加入 h[k] = value)
				// 存在返回value存的位置,通过h[k]可以找到value
}

拉链法

思路

拉链法是在每个存放数据的地方开一个链表,如果有多个value对应的 key (key = value % N) 索引到同一个地方,只用把他们都放到那个位置的链表里就行了。查询的时候需要把对应位置的链表整个扫一遍。
在这里插入图片描述

数组链表实现:

void insert(int v)
{
	int k = (v % N + N) % N;
	e[idx] = v; // idx结点
	ne[idx] = h[k]; // 下一个结点
	h[k] = idx++; // 更新链
}

int find(int v)
{
	int k = (v % N + N) % N;
	for (int i = h[k]; i != -1; i = ne[i]) // h[k]初始值为-1,-1为空
		if (e[i] == v) return true;
	return false;
}

以上的N均取大于输入数据范围的最小质数。


字符串哈希

字符串匹配

求出模式串的哈希值后,求出文本串每个长度为模式串长度的子串的哈希值,分别与模式串的哈希值比较即可。
例:文本串aabbaa对应的存放方法
h[1] = a , h[2] = aa,h[3] = aab , h[4] = aabb , h[5] = aabba , h[6] = aabbaa
实际哈希数组h不是字符类型,所以要将字符转换成数字这里称哈希值

哈希值求法

  1. 哈希值是一个p进制数,公式为 h[i] = (h[i-1] * p + 对应最后一个字符的ASCII码值) % Q
    例:h[1] = 0 * p + 97(a的ascll) , h[2] = h[1] * p + 97 ······(不管Q后面会讲)
  2. 哈希值不一样时要保证两个字符串大概率不一样(一般可以将大概率看成一定)。
    p值取131 或 13331Q值取264 就表示近似 避免冲突。
  3. Q 值在计算中不必写出来,只要将h数组类型写成unsigned long long就可以代替。

区间哈希值求法

  1. 例:12345十进制数要求第四位( l = 4)到第五位 ( r = 5 )的值。
    很显然值为45,方法: 12345 - 123 * 100 = 45
  2. 同理 要求字符aabbaa第四位( l = 4)到第五位 ( r = 5 )的哈希值。
    方法:hash = h[5] - h[3] * p ^ (5-3)

总结区间哈希值公式为:h[l,r] = h[r] − h[l−1] × p^(r−l+1)

代码实现

typedef unsigned long long ull;

const int p = 131;

ull q[N],h[N]; //q数组为p的n次方

ull get(int l, int r)
{
	return h[r] - h[l - 1] * q[r - l + 1]; //区间哈希值求法公式
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值