蓝书《哈希与哈希表》——知识整理

一、前言:

  有些数据不经处理是难以利用的。所谓哈希,就是通过哈希函数将这种难以简单利用的数据(比如矩阵、字符串等等)转化为可以用一个变量表示甚至可以作为数组下标的哈希值。有了哈希值,就可以实现时间复杂度近乎为常数的快速查找与匹配,更简单有效地利用一些复杂数据。

二、字符串哈希:

  即对象为字符串的哈希。常将字符串看做一个不严格的b进制的数(有时数位上的数有可能要比b还要大),转换为10机制后再模一个数p(以便存储)得到哈希值。即定义哈希函数:

    H(C)=(c1*b^(m-1) + c2*b^(m-2) + . . . + c0*b^0)% p

      (c为字符串,m为字符串长度)

  当两字符串的哈希值相同时,我们就认为这两个字符串是一模一样的。显然这样的判断有时会有“冲突”,即相同哈希值的两个字符串可能会不同。而冲突的概率显然与p和b有关。一般来说,p的因数越多,冲突概率越大(故p一般选大素数)。

  做子串匹配时,我们要知道所有子串的哈希值。难道要用O(n^2)的复杂度全部处理出来吗?这里有一个叫做滚动哈希的优化技巧,实质是用了前缀和与递推的思想,同时我们可以用unsigned int 型,用自然溢出时对2^32取模来代替手写取模:

    设H(C,k)为字符串c前 k 个字符构成的字符串的哈希值,发现H(C,k+1)= H(C,k) * b+c[k+1]);

    主串上某一子串c[k]c[k+1]...c[k+len]的哈希值即=H(C,k+len) - H(C,k-1) * b^n;

  这样只要预处理出b的次幂再用O(n)的时间处理出H(C,1)...H(C,m),主串所有子串的哈希值也就知道了。

  平时常应用与各种字符串匹配问题。为了进一步降低冲突概率,还可以再另处理一组哈希值,称为“双哈希”,此时取模的素数常用1e9+7和1e9+9,这两个孪生素数可以将随机数据的冲突概率降到1/(1000000009*1000000007)(当然还是防不了毒瘤出题人故意出一个卡哈希的数据,OIer与出题人的斗智斗勇永不停息......)

三、哈希表:

  运用哈希可以将大的数据转化为较小的哈希值,同时发现如果哈希函数选取合适,那么相同哈希值的不同元素会非常少。由此提醒我们可以搞一个可以快速查询元素的结构——哈希表:

  在一个相同哈希值的域下记录相应数据。在一个哈希表中查询数据x时,算出x的哈希值h=H(x),将h域下所有的元素与x进行比较(不会很多),得出结果。

  通常用邻接链表实现哈希表,代码这里不写出了,蓝书70页写的很详细。代码中H变量没提到值,应该等于b,注意一下插入数据时先判个重。

  最后有一个小技巧:如果真实数据过大,域下记录的数据可以是模另一个素数的余数,达到“双哈希”的效果。

  

原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/11219223.html

时间: 2024-08-29 17:39:00

蓝书《哈希与哈希表》——知识整理的相关文章

【哈希和哈希表】Beads

问题 G: [哈希和哈希表]Beads 时间限制: 1 Sec  内存限制: 128 MB提交: 6  解决: 2[提交] [状态] [讨论版] [命题人:admin] 题目描述 Byteasar once decided to start manufacturing necklaces. He subsequently bought a very long string of colourful coral beads for a bargain price. Byteasar now als

【模版】简单哈希和哈希表处理冲突

哈希(Hash)算法就是单向散列算法,它把某个较大的集合P映射到另一个较小的集合Q中.数学原理听起来很抽象,在网上找到一个很生动的描述.我们有很多的小猪,每个的体重都不一样,假设体重分布比较平均(我们考虑到公斤级别),我们按照体重来分,划分成100个小猪圈. 然后把每个小猪,按照体重赶进各自的猪圈里,记录档案.如果我们要精确找到某个小猪怎么办呢?我们需要每个猪圈,每个小猪的比对吗? 当然不需要了. 我们先看看要找的这个小猪的体重,然后就找到了对应的猪圈了. 在这个猪圈里的小猪的数量就相对很少了.

蓝书例题之UVa 10253 Series-Parallel Networks

挺有趣的一道题 首先转化模型,思路参考蓝书,可得出等同于求共n个叶子,且每个非叶结点至少有两个子结点的无标号树的个数的二倍,设个数为\(f[n]\) 考虑怎么求\(f[n]\),假设有一个\(n\)的整数划分,分别代表每棵子树中的叶节点个数,然后用可重组合,乘法原理和加法原理把\(f[n]\)递推出来 这个过程可以用\(dp\)来完成,设\(g[i][j]\)表示子树中叶结点数量最大值小于等于\(i\),共有\(j\)个叶结点的树的个数,转移时枚举最大的叶结点数量\(i\)和叶结点数量为\(i\

0x46蓝书习题:普通平衡树

Treap/平衡二叉树 蓝书习题:普通平衡树 这道题是一道平衡树模板题,可以用多种解法,这里用最简单的Treap,下面简单说一下各种操作的思路 添加: 当要添加一个值时,先判断所要加入的以p为根节点的子树是否为空,为空添加新的节点:New(val). 当然平衡树,当加入新节点后,子节点dat变得大于a[p].dat时,要旋转,左旋右旋见代码,好理解. void Insert(int &p,int val){ if(!p){ p=New(val); return; } if(val==a[p].v

计算数据库中各个表的数据量和每行记录所占用空间--添加架构信息-读后感及知识整理

参考文章: SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database) 分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 监控SQLServer 数据库表每天的空间变化情况 仔细拜读上面三位的文章,不会的知识点又参考了MSDN,巩固了知识点如下: 知识点: 1.表的架构信息,涉及的系统对象 sys.schemas 和 INFORMATION_SCHEMA.TABLES,但后者不是官方推荐方式,

C#与C++数据类型对应表(搜集整理一)

C#与C++数据类型对应表(搜集整理一) C#与C++数据类型对应表   C#调用DLL文件时参数对应表 Wtypes.h 中的非托管类型 非托管 C 语言类型 托管类名 说明 HANDLE void* System.IntPtr 32 位 BYTE unsigned char System.Byte 8 位 SHORT short System.Int16 16 位 WORD unsigned short System.UInt16 16 位 INT int System.Int32 32 位

MySQL数据表碎片整理

在MySQL中,我们经常会使用VARCHAR.TEXT.BLOB等可变长度的文本数据类型.不过,当我们使用这些数据类型之后,我们就不得不做一些额外的工作--MySQL数据表碎片整理. 那么,为什么在使用这些数据类型之后,我们就要对MySQL定期进行碎片整理呢? 现在,我们先来看一个具体的例子.在这里,我们使用如下SQL语句在MySQL自带的TEST数据库中创建名为DEMO的数据表并插入5条测试数据. --创建DEMO表  id int unsigned,  body text  ) engine

MySQL关于表碎片整理OPTIMIZE TABLE操作

MySQL关于表碎片整理OPTIMIZE TABLE操作的官方建议1.MySQL官方建议不要经常(每小时或每天)进行碎片整理,一般根据实际情况,只需要每周或者每月整理一次即可,可以写成定时任务来做.2.OPTIMIZE TABLE只对MyISAM,BDB和InnoDB表起作用,尤其是MyISAM表的作用最为明显.此外,并不是所有表都需要进行碎片整理,一般只需要对包含上述可变长度的文本数据类型的表进行整理即可.3.在OPTIMIZE TABLE运行过程中,MySQL会锁定表.4.默认情况下,直接对

CRM中QueryDict和模型表知识补充

1.QueryDict的用法 request.GET的用法:1.在页面上输入:http://127.0.0.1:8000/index/print(request.GET,type(request.GET))<QueryDict: {}> <class 'django.http.request.QueryDict'>在收到GET请求后,Django会将后面的参数以字典的形式接收.如果无参数就显示空字典2.在页面上输入:http://127.0.0.1:8000/index/?page