哈希表

哈希表是一种通过映射来快速查找的数据结构。其通过键值对(key-value)来存储。一个数据通过哈希函数的运算来生成一个属于他自己的键值,尔后将其与键值绑定。当我们想查找这个数据时,就可以直接通过键来访问对应的值,时间复杂度近似为O(1)。

哈希表适用于这样一种场景,当数据范围很大但是数据量很小时(不要求保序,若保序可以考虑离散化),或者对于一个字符串我们想要使用数字值对其做出映射时(字符串哈希),都可以使用哈希表来存储,当查找对应值时,只需要计算出键来找就好了。而不需要从头到尾遍历。

数字哈希

对于数据规模为N一个数字,我们可以给出这样一个简单的哈希函数

int get_key(int x)
{
return x % N;
//若考虑x可能为一负数
return (x % N + N) % N;
}

显然对于数据范围内的数据,计算出的哈希值肯定会有所冲突,这就导致一个哈希值无法对应多个数据的存储。这里给出解决冲突的两个方案,分离链接法(拉链法)以及开放定址法

分离链接法(拉链法):



示意图如上

顾名思义,拉链法就是在对应每个哈希值下建立一条链表,当该哈希值有元素要加入时,就在对应哈希值的链表上插入一个新节点。(有点像邻接表)在查找时,我们根据对应的哈希值来遍历整条链表来寻找对应元素。链表的实现可以使用数组模拟,也可以这样

vector<int>h[N];

这样每一个数组元素都是一个节点,链表插入元素也就变为了h[i].push_back(x);

开放定址法:

开放定址法的实现很简单。在初始化存储数组时,将其中的元素都置为一不可触碰到初始值(如负数或者无穷大0x3f3f3f3f)。当遇到冲突时,我们就接着看下一个存储位置是否没有元素存储,直到找到一个没有元素存储的位置,存储进去。查找时也是,若当前位置已经有元素了,且该元素不为空,就接这查找下一个元素,直到找到x == hi,或者h[i]为空(该表中没有该元素)时截止。

下面给出分离链接法以及开放定址法实现的代码

分离链接法

void insert(int x)
{
int k = get_hash(x);
h[k].push_back(x);//加入到链表中
}
bool query(int x)
{
int k = get_hash(x);
for (int i = 0; i < h[k].size(); i++)//遍历整条链表
{
if (h[k][i] == x)
return true;
}
return false;
}

开放定址法

void insert(int x) // 开放定址法
{
int k = get_hash(x);
while (h[k] != null) k++; //若当前位置不为空,向后移一位直到找到空位置
h[k] = x;
}
bool query(int x)
{
int k = get_hash(x);
while (h[k] != null && h[k] != x) k++; //若当前位置不空且并非所查节点,向后移一位
if (h[k] == x)
return true; //若能找到这样的节点,则hashmap中有该元素
else
return false;//否则代表hashmap中没有该元素
}

最后还有一点需要提醒的是,据经验所得,哈希表的大小N一般取为素数。对于分离链接法取大于数据规模的第一个素数,而对于开放定址法一般取大于数据规模2-3倍的第一个素数,这样的话会使得冲突的概率比较小

字符串哈希

对于数字可以将其映射,那么,对于存储起来比较麻烦的字符串,我们也可以构造一个合适的哈希函数,将一个字符串映射到一个哈希值上,从而达到以较快的速度来处理字符串的查找与对比。

对于字符串的哈希,我们给出这样的思想,将一个长度为p的字符串看作一个p进制数,其哈希函数就是将字符串从p进制转换为十进制。

比如二进制数1010,其基数为2,转换成对应的十进制数时,最低位的权值为0,权值依此逐渐上升。则1010对应的十进制数为$$ 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 0 * 2^0 = 10$$。对应的一个p进制数的基数就是p。

举个例子。给出字符串abc,假设其为131进制数,则其对应的十进制数为$$ 'a' * 131^2 + 'b' * 131^1 + 'c' * 131^0 $$,字符取其对应的ascii码来计算,最后防止数据太大,将结果模上一个较大的数如2^64

需要用到字符串哈希的题目,常常是需要给出一个较长的字符串,然后给出n次询问,每次查询该字符串的两个区间内的字串是否相等,这就要求我们能快速求出一个字符串中任意区间内字符的长度,显然,应用前缀和算法可以实现这一点

注意,根据经验,当进制p = 131,mod = 2^64时,字符串哈希可以视为没有冲突。由于字符串哈希计算时仅涉及正数,因此数据可以使用unsigned long long 类型(8个Byte,64个bit,最多存储2^64 - 1个数)来存储,当数据超过2^64 -1溢出时,其效果等于mod 2^64

下面给出预处理字符串哈希前缀和的代码

const int N = 1e5+10,P = 131;
typedef unsigned long long ull;
ull h[N],p[N]; void pre_process(char s[])
{
p[0] = 1;
h[0] = 0;
for (int i = 1; s[i]; i++)
{
p[i] = p[i - 1] * P;//p[i]存储的是p^i次幂,后面有用
h[i] = h[i - 1] * P + s[i];
}
}

预处理之后如何求出对应区间内的哈希值呢?

给出左右端点[l,r], 其右端点的前缀和哈希为

\[s[0] * p^{r-1} + s[1] * p^{r-2} + ... + s[l - 1] * p^{r - l + 1} + s[l] * p^{r - l} + ... + s[r] * p^0
\]

而其左端点减1的前缀和哈希为(即l - 1)

\[s[0] * p^{l-2} + s[1] * p^{l - 3} + ... + s[l - 1] * p^0
\]

显然,我们让2式乘以 r - l + 1,让其左端与1式对齐得到如下式子

\[s[0] * p^{r-1} + s[1] * p^{r - 2} + ... + s[l - 1] * p^{r - l + 1}
\]

1式减2式,得如下

\[s[l] * p^{r - 1} + s[l - 1] * p^{r - 2} + ... + s[r] * p^0
\]

可以看出,最后得出的三式就是从l到r的前缀哈希和因此我们得出了这样一个公式。要计算从l到r的前缀哈希和,按照下面公式即可

\[ans = h[r] - h[l-1] * p[r - l + 1]
\]

所以得出以下函数

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

当我们想要比对两个字符串是否相等时,只需要比对两个字符串的哈希值是否相等即可。给出例题

字符串哈希

STL中的哈希表

在STL库中,unordered_map类是一个已经实现好的哈希表,其初始化如下

#include <unordered_map>
using namespace std;
int main()
{
unordered_map<string,int> a;//哈希表的键类型和值类型可以任意
//向哈希表中插入一个元素有如下几种方法
a.insert({"try1",1});//insert参数为一个pair
a.emplace("try2",2);//emplace第一个参数为键,第二个参数为值
a["try3"] = 3;//unordered_map重载了数组运算符,使之可以直接用来添加元素(类似于py中的字典)
//当我们想要访问其中的元素时,只需要想使用数组一样,不过索引为对应键值
cout << a["try1"] << endl;
cout << a["try2"] << endl;
cout << a["try3"] << endl;
return 0;
}
//unordered_map的时间复杂度近似O(1)

哈希表(HashMap)与字符串哈希的更多相关文章

  1. 【二分答案】【哈希表】【字符串哈希】bzoj2946 [Poi2000]公共串

    二分答案,然后搞出hash值扔到哈希表里.期望复杂度O(n*log(n)). <法一>next数组版哈希表 #include<cstdio> #include<cstri ...

  2. 深入理解PHP内核(六)哈希表以及PHP的哈希表实现

    原文链接:http://www.orlion.ga/241/ 一.哈希表(HashTable) 大部分动态语言的实现中都使用了哈希表,哈希表是一种通过哈希函数,将特定的键映射到特定值得一种数据 结构, ...

  3. 数据结构 5 哈希表/HashMap 、自动扩容、多线程会出现的问题

    上一节,我们已经介绍了最重要的B树以及B+树,使用的情况以及区别的内容.当然,本节课,我们将学习重要的一个数据结构.哈希表 哈希表 哈希也常被称作是散列表,为什么要这么称呼呢,散列.散列.其元素分布较 ...

  4. 数据结构 哈希表(Hash Table)_哈希概述

    哈希表支持一种最有效的检索方法:散列. 从根来上说,一个哈希表包含一个数组,通过特殊的索引值(键)来访问数组中的元素. 哈希表的主要思想是通过一个哈希函数,在所有可能的键与槽位之间建立一张映射表.哈希 ...

  5. java哈希表(线性探测哈希表。链式哈希表)

    哈希表(散列表) 通过哈希函数使元素的存储位置与它 的关键码之间能够建立一一映射的关系,在查找时可以很快找到该元素. 哈希表hash table(key,value) 的做法其实很简单,就是把Key通 ...

  6. java集合-哈希表HashMap

    一.简介 HashMap是一个散列表,是一种用于存储key-value的数据结构. 二.类图 public class HashMap<K,V> extends AbstractMap&l ...

  7. Java知多少(79)哈希表及其应用

    哈希表也称为散列表,是用来存储群体对象的集合类结构. 什么是哈希表 数组和向量都可以存储对象,但对象的存储位置是随机的,也就是说对象本身与其存储位置之间没有必然的联系.当要查找一个对象时,只能以某种顺 ...

  8. 从HashMap透析哈希表

    ##扯数据结构 先看一下哈希表的概念: 哈希表是一种数据结构,它可以提供快速的插入操作和查找操作.第一次接触哈希表,他会让人难以置信,因为它的插入和删除.查找都接近O(1)的时间级别.用哈希表,很多操 ...

  9. Swift4 基本数据类型(范围型, Stride型, 数组, 字符串, 哈希表)

    创建: 2018/02/28 完成: 2018/03/04 更新: 2018/05/03 给主要标题加上英语, 方便页内搜索 [任务表]TODO 范围型(Range)与Stride型  与范围运算符相 ...

  10. java数据结构和算法09(哈希表)

    树的结构说得差不多了,现在我们来说说一种数据结构叫做哈希表(hash table),哈希表有是干什么用的呢?我们知道树的操作的时间复杂度通常为O(logN),那有没有更快的数据结构?当然有,那就是哈希 ...

随机推荐

  1. Ipa Guard使用手册

    ​ 使用手册 开始使用ipa guard 代码混淆界面介绍 文件混淆-界面介绍 安装和登录Ipa Guard 相关教程 下载安装Ipa Guard ipaguard注册和登录 下载安装Ipa Guar ...

  2. 1688 复杂业务场景下的 Serverless 提效实践

    1688 复杂业务场景下的 Serverless 提效实践 作者 | 远岩(阿里巴巴 CBU 技术部 Serverless & 工程效能负责人) 前言 首先为大家简单介绍一下我们的业务场景,1 ...

  3. 微信小程序图片展示类型

  4. java基础(4)--javadoc文档与命令

    一.Javadoc文档 javadoc是Sun公司提供的一个技术,它从程序源代码中抽取类.方法.成员等注释形成一个和源代码配套的API帮助文档.也就是说,只要在编写程序时以一套特定的标签作注释,在程序 ...

  5. java项目实战-spring-基本用法01-day24

    目录 1. spring 简单介绍 2. IOC/DI --控制反转--是啥 3. 实现 3. 如果 对象的 属性为引用数据类型 如何 实例化对象 4 如何用注解的方式 以少量的代码实现对象的创建于获 ...

  6. P1047 [NOIP2005 普及组] 校门外的树

    1.题目介绍 [NOIP2005 普及组] 校门外的树 题目描述 某校大门外长度为 \(l\) 的马路上有一排树,每两棵相邻的树之间的间隔都是 \(1\) 米.我们可以把马路看成一个数轴,马路的一端在 ...

  7. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2024.01.03)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  8. [转帖]充分利用 Oracle SQL监控

    https://zhuanlan.zhihu.com/p/397834311 经常被问到查看执行计划的最佳工具是什么,对我来说,答案总是SQL Monitor(包含在 Oracle Tuning Pa ...

  9. [转帖]Linux块层技术全面剖析-v0.1

    Linux块层技术全面剖析-v0.1 perftrace@gmail.com 前言 网络上很多文章对块层的描述散乱在各个站点,而一些经典书籍由于更新不及时难免更不上最新的代码,例如关于块层的多队列.那 ...

  10. [转帖]Arm CPU风起,补齐国产大芯片最后一块拼图 | 甲子光年

    https://rmh.pdnews.cn/Pc/ArtInfoApi/article?id=30960014 最近一年,国产CPU火了. 今年6月24日,龙芯中科在科创板挂牌上市,公司主营自研Loo ...