介绍

哈希算法是通过一个哈希函数,将一段数据(也包括字符串、较大的数字等)转化为能够用变量表示或是直接就可作为数组下标的数字,这样转化后的数值我们称之为哈希值, 也就是算出一个数来代表一个字符串。

我们通过哈希值从而实现很快地查找和匹配,

常用:字符串Hash和哈希表。

字符串Hash流程

如果我们用O(m)的时间来计算长度为m的字符串的哈希值,则总的时间复杂度并没有改观,这里就需要用到一个叫做滚动哈希的优化技巧。

我们选取两个合适的互素常数b(进制)和h(模数)(b < h),假设字符串C =c1c2...cm,那么我们定义哈希函数:

正常的数字是十进制的,这里b是基数,相当于把字符串看做是b进制数。

这一过程是递推计算的,设H(c, k)为前k个字符的构成的字符串的哈希值,则:(以下均不考虑取模的情况)

如字符串C=“ACDA”(为方便处理,我们令‘A’表示1,‘B’表示2,以此类推),则:

通常题目要求的判断字符串C 从位置k+1开始的长度为n的子串C'=ck+1ck+2...ck+n的哈希值与另一匹配串S = s1s2...sn的哈希值是否相等,则:

于是只要预处理出bn,就能在O(1)时间内得到任意的字符串子串哈希值,从而完成字符串匹配,那么上述字符串匹配问题的总复杂度就为O(n + m)。

如字符串C=“ACDA”,S=”CD”,当k=1, n=2时:

因此子串C'与匹配串S匹配。

在实现时,可以利用64位无符号整数计算哈希值,即取h=2^64,通过自然溢出省去求模运算。

字符串Hash正确性

字符串Hash对于任意不同的字符串所产生的哈希值必然是互不相同的吗?显然不是的,但概率很低,在竞赛中我们常常认为这种情况不会发生。

即便如此,我们还可以再用“双哈希”降低出现相同哈希值的概率,即取不同的模数,把不同模数算出的哈希值都记下来,只有几个哈希值都一样,我们才能判定匹配。我们通常用双哈希就可以将冲突的概率降到很低,如果分别取h=10^9+7和h=10^9+9,就几乎不可能发生冲突,因为他们是一对“孪生素数”。


【例题1】Oulipo(信息学奥赛一本通 1455)

【题目描述】

给出两个字符串s1,s2((只有大写字母),求s1在s2中出现多少次。 例如:s1="ABA",s2="ABAABA",答案为2。

【输入】

输入T组数据,每组数据输出结果。

【输出】

如题述。

【输入样例】

3

BAPC

BAPC

AZA

AZAAZAAZA

VEEDI AVERDXIVYERDLAN

【输出样例】

1

3

0


哈希表流程

现在要存储和使用下面的线性表:A(1,75,324,43,1353,91,40)。

定义一个一维数组A[1...n],此时n=7,将表中元素按大小顺序存储在A[i]中,但这样就算使用二分查找,我们仍需要用O(log n)的时间去查找某个元素。

为了用O(1)的时间实现查找,可以开一个一维数组A[1...1353],使得A[key]=key,但显然造成了空间上的很大浪费,尤其是数据范围很大时。

为了使空间开销减少,我们可以对第二种方法加以优化,设计一个哈希函数H(key) = key mod 13,然后令A[H(key)]=key,这样一来定义一个一维数组A[0...12]就已足够,这种方法就是哈希表。

但刚才那样的存储是有问题的,如H(1)=H(40)=1,在存储40时又把1给覆盖掉了,那么查询就会出现错误,这种不同的数据产生相同哈希值的情况我们称之为冲突。

这里与字符串Hash有所不同,可能不论我们怎样选用哈希函数,还是很难避免产生冲突。

因此我们考虑对每一个哈希值记一个链表(其实也就相当于邻接表),把所有等于同一个哈希值的数字都存储下来,而查询只要遍历对应的链表即可,这样实际复杂度取决于查询的链表长度,也可以看做是常数级。

例如我们定义哈希函数H(x) = x mod 16,插入一些数据的效果如下图。

哈希函数的构造

通常情况下,我们用除余法来构造哈希函数。 ·即选择一个适当的正整数b,用其对取模的余数作为哈希值。

其关键是b的选取,为了尽量避免冲突,一般选为能够存储下并且尽量大的素数(一般情况下我们根据空间取10^6左右的素数)。一般地说,如果b的约数越多,那么冲突的几率就越大。

using namespace std;
const int N = 50000;             //定义总共存入哈希表的数字个数
const int b = 999979;             //定义哈希函数中的模数
int tot, adj[H], nxt[N], num[N]];                void insert(int key)  //将一个数字插入哈希表
{            int h = key % b;                  //除余法 for (int e = adj[h]; e; e = nxt[e]) {    if (num[e] == key) return ;      }         //如果链表中已经出现过当前的数字就不用再存储一遍nxt[++tot] = adj[h], adj[h] = tot;          num[tot] = key;  //建立链表,存储下所有哈希值等于h的数字
 }          bool query(int key)  //查询数字x是否存在于哈希表中
{            int h = key % b;                  //同样先进行取余,求其哈希值  for (int e = adj[h]; e; e = nxt[e])         if (num[e] == key) return true; //查询对应链表,查询到则表示存在 return false;                       //不存在返回 false
  }
} 


【例题2】图书管理(信息学奥赛一本通 1456)

【题目描述】

图书管理是一件十分繁杂的工作,在一个图书馆中每天都会有许多新书加入。为了更方便的管理图书(以便于帮助想要借书的客人快速查找他们是否有他们所需要的书),我们需要设计一个图书查找系统。 该系统需要支持 2 种操作: add(s) 表示新加入一本书名为 s 的图书。 find(s) 表示查询是否存在一本书名为 s 的图书。

【输入】

第一行包括一个正整数 n,表示操作数。 以下 n 行,每行给出 2 种操作中的某一个指令条,指令格式为:add s 或 find s 在书名 s 与指令(add,find)之间有一个隔开,我们保证所有书名的长度都不超过 200。可以假设读入数据是准确无误的。

【输出】

对于每个 find(s) 指令,我们必须对应的输出一行 yes 或 no,表示当前所查询的书是否存在于图书馆内。 注意:一开始时图书馆内是没有一本图书的。并且,对于相同字母不同大小写的书名,我们认为它们是不同的。

【输入样例】

4

add Inside C#

find Effective Java

add Effective Java

find Effective Java

【输出样例】

no

yes

转载于:https://www.cnblogs.com/ljy-endl/p/11462207.html

哈希和哈希表(超详细!!!)相关推荐

  1. 【内卷数据结构】顺序表超详细解析 | 从零开始步步解读 | 画图理解+调试分析 | 菜单制作

    ​​​​ 前言: 本章节将对顺序表的概念进行介绍,着重讲解动态顺序表.对常用的接口函数进行一个个讲解,并进行解析.顺序表讲解部分将从零实现顺序表接口函数,遇到问题我会进行一步步地调试说明,通过对本章的 ...

  2. 数据结构与算法之线性表(超详细顺序表、链表)

    原创公众号:bigsai 文章已收录在 全网都在关注的数据结构与算法学习仓库 欢迎star 前言 通过前面数据结构与算法基础知识我么知道了数据结构的一些概念和重要性,那么我们今天总结下线性表相关的内容 ...

  3. C++哈希表最详细解决

    目录 1 哈希表理论基础 1. 1 哈希函数 1.2 哈希碰撞 2 哈希表力扣题参考代码 原文链接  代码随想录 1 哈希表理论基础 首先什么是 哈希表,哈希表(英文名字为Hash table,国内也 ...

  4. 提高篇 第二部分 字符串算法 第1章 哈希和哈希表

    浅谈字符串哈希_1264Ikaros的博客-CSDN博客_字符串哈希 图书管理-哈希表_handsome·wjc的博客-CSDN博客 字符串哈希 哈希表 - DTTTTTTT - 博客园 图书管理(L ...

  5. Java集合—哈希(hash)表

    原文作者: 原文地址: 1.哈希表的定义 这里先说一下哈希(hash)表的定义:哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方,说起来可能感觉有点复杂,我 ...

  6. 哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶

    文章目录 哈希 哈希(散列)函数 常见的哈希函数 字符串哈希函数 哈希冲突 闭散列(开放地址法) 开散列(链地址法/拉链法) 负载因子以及增容 对于闭散列 对于开散列结构 具体实现 哈希表(闭散列) ...

  7. 不同表结构数据迁移_数据结构:哈希 哈希函数 哈希表

    写在前面 希望你们看了能够有所收获,同时觉得不错的朋友可以点赞和关注下我,以后还会有更多精选文章分享给大家!大家可以关注一下java提升专栏 java提升​zhuanlan.zhihu.com 什么是 ...

  8. 【哈希和哈希表】Beads

    问题 G: [哈希和哈希表]Beads 时间限制: 1 Sec  内存限制: 128 MB 提交: 6  解决: 2 [提交] [状态] [讨论版] [命题人:admin] 题目描述 Byteasar ...

  9. 高级数据结构与算法 | 哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶

    文章目录 哈希 哈希函数 常见的哈希函数 字符串哈希函数 哈希冲突 闭散列的解决方法 开散列的解决方法 负载因子以及增容 对于闭散列 对于开散列结构 具体实现 哈希表(闭散列) 插入 查找 删除 完整 ...

  10. 哈希值 哈希表_哈希杰森

    哈希值 哈希表 我最近写了一个简单的库,可预测地对json进行哈希处理 . 该实用程序基于出色的Jackson Json解析库构建 问题 我需要从相当大的基于json的内容生成的哈希值,以便稍后确定该 ...

最新文章

  1. GNSS NMEA ddmm.mmmmm格式转换
  2. python爬虫,爬取猫眼电影1(正则表达式)
  3. lucene源码分析(4)Similarity相似度算法
  4. LLBLGen 关于类型转换
  5. 55. Jump Game
  6. java的throw_浅谈Java的throw与throws
  7. 交换机的基本配置实验报告_无线网络设计配置即实验报告
  8. MySQL数据库优化(五)
  9. Win-MASM64汇编语言-PTR运算符
  10. 3年了,我依旧单身,而微信小程序已经普及了
  11. Maven插件:versions-maven-plugin
  12. java 标准_Java标准注解
  13. FFmpeg源代码简单分析:av_write_trailer()
  14. sudo: must be setuid root错误解决方法.
  15. AI和大数据结合,智能运维平台助力流利说提升竞争力
  16. 在Ubuntu中搭建NFS服务器
  17. 网络协议详解1 - NBNS
  18. 阿里云MVP精选2018年终盘点:大咖专访+最佳实践,丰富干货等你来!
  19. r语言是高级编程语言_R编程语言介绍
  20. Vue+高德地图API的使用(点击地图搜索周边信息)

热门文章

  1. Apple 无线鼠标、键盘或触控板各型号的Mac系统要求和区别
  2. 古人的白酒度数有多高,为何能够做到千杯不醉?
  3. mySQL清清除特殊格式
  4. 【模型性能1-泛化原因分析】On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima
  5. iOS中黄色文件夹和蓝色文件夹的区别
  6. 如何还原 Active Directory 中已删除的对象
  7. 基于JavaEE(JSP)的共享资料平台的设计与实现
  8. 非锐化掩蔽和高提升滤波
  9. (个人)AR电子书系统创新实训第五周(2)
  10. PHP使用CURL详解