python数据结构与算法 29-1 哈希查找

前面的章节中,我们利用数据集中元素的相对位置信息来提高查找算法的性能。

比方知道列表是有序的,能够使用二分查找。本节我们走得更远一些,创建一个数据结构,使得查找性能提高到O(1)。称为哈希查找。

要做到这种性能,我们要知道元素的可能位置。假设每一个元素就在他应该在的位置上,那么要查找的时候仅仅须要一次比較得到有没有的答案,但以下将会看到。不是这么回事。

哈希表是这样一种数据集合,元素的保存的时候就存在easy找到位置上。哈希表表中每个位置,一般称为槽位,每个槽位都能保存一个数据元素并以一个整数命名(从0開始)。这样我们就有0号槽位。1号槽位等等。起始时。哈希表里没有数据,槽位是空的。这样在构建哈希表的时候,能够把槽位值都初始化为None,图4显示一个大小为11的哈希表,或者是说有m个槽位的哈希表。m从0到10.

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHl0aG9uMjAxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

图中元素和保存的槽位之间的映射关系,称为哈希函数,哈希函数接受一个元素作为參数,返回一个0到m-1的整数作为槽位名。假如我们有一个整数集54,26,93。17,77和31,我们的第一个哈希函数就能够用“余数法”。简单地将元素除以表的大小,返回余数作为哈希值。(h(item)=item%11)。表4是上述整数集的哈希值。


Table 4: Simple Hash Function Using Remainders


Item


Hash Value


54


10


26


4


93


5


17


6


77


0


31


9

注意余数法一般以某种形式存于全部哈希函数中。由于它的结果一定在槽位范围内。

一旦哈希值计算出来,就要把元素插入到哈希表中指定的位置。

如图5所看到的,注意6槽位和11槽位是空的,这就要引入满载因子的概念,一般表述为:

λ=元素数量/哈希表容量

这里。就是

λ=6/11

如今当我们要查找的时候,仅仅要简单地用哈希函数计算出槽位值。然后到表中检查是否存在就能够了,这个查找动作是O(1),由于计算哈希值的时间。以及到表中查找的时间是个常数。假设每件东西都各守其位。我们就发现了一个常数级的查找算法。

或许你已经注意到,这个技术仅在每一个元素相应一个位置时有效,比如,上面的样例中假设添加一个44。那么它的哈希值是0。可是77的值也是0。这时问题就出来了。2个值相应同一个槽位,这被称为“collision”,非常明显,collision给哈希技术造成了困难,我们随后具体讨论。

哈希函数

对给定的数据集,哈希函数将每一个元素映射为单个的槽位。称为“完美哈希函数”,假设我们知道元素和集合固定不变。那么构造一个完美哈希函数或许是可能的。坏消息是对一个随意数据集合,没有一个系统的方法来构造完美哈希函数,好消息是。哈希函数不完美也能提供不错的性能。

假设一定要完美的哈希函数,一种方法是做大哈希表,以保证每一个元素都有自己的索引。

尽管在数据不多的情况下可行,可是假设数据非常大就不可行。

比方,假设数据项是8位号码,这就须要十亿个槽位。要是我们只用来保存25个学生的号码,就太费了。

我们的目标是:collision最少,计算简单,分布均匀。有几种扩展余数法的方案,以下讨论当中几个。

折叠法:这样的方法把元素分成相等的几片(最后一片可能不相等)。然后再把碎片拼起来作为哈希值。比方我们的数据项是号码436-555-4601,那么应该把号码分成2个一组,然后加起来,即43+65+55+46+01,得到210 。如果哈希表有11个槽位。那么再一步用11除210来得到槽位。即210%11=1。所以号码436-555-4601的哈希值是1 。有些折叠法多了一步,在相加之前,把数据位顺序反转,在上面的样例中。即 43+56+55+64+01=219 计算219 % 11=10。

还有一种算法叫做“平方取中法”,先计算元素的平方值,再从中提取几位数字。比如,对元素44。先计算442=1936。提取中间两位93,然后再取余数法,得到5(93%11=5)


Table 5: Comparison of Remainder and Mid-Square Methods

表5 余数法与平方取中法的比較


Item


Remainder


Mid-Square


54


10


3


26


4


7


93


5


9


17


6


8


77


0


4


31


9


6

对于字符类元素也能创建哈希函数,单词cat能够看成一个数字串

>>> ord(‘c‘)
99
>>> ord(‘a‘)
97
>>> ord(‘t‘)
116

我们把这三个数字加起来,用余数法计算哈希值。

以下是一个计算字符串哈希值的函数:

Listing 1

defhash(astring, tablesize):
    sum=0
    for pos inrange(len(astring)):
        sum=sum+ord(astring[pos])
 
    returnsum%tablesize

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHl0aG9uMjAxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

有意思的是,上述算法中。同样字母不同顺序的单词得到的哈希值相等,解决的方法是加上字母的位置作为重量。图7显示了使用位置作为重量因子。改动后的哈希函数作为练习。

你也能够思考几种计算哈希值的方法,但必需要记住,哈希函数必需要简单高效。不能成为计算的主要负担。假设哈希函数太复杂,计算槽位名的时间超过了简单的顺序查找或二分查找的时间。那么哈希函数还有什么意义呢?

时间: 2024-08-03 08:44:28

python数据结构与算法 29-1 哈希查找的相关文章

在路上---学习篇(一)Python 数据结构和算法 (5)二分查找、二叉树遍历

独白: 利用算法进行查找指定元素,最近学习二分查找和二叉树遍历.二分查找前提是在有序中进行查找,二叉树引入了树的概念.树的概念其中有许多小知识点,也是一种新的数据结构.还是之前的感悟,需了解其本质才会写出更好的算法. 二分查找 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用

python数据结构与算法 38 分析树

分析树 树的结构完成以后,该是时候看看它能做点什么实事儿了.这一节里,我们研究一下分析树.分析树能够用于真实世界的结构表示,象语法或数学表达式一类的. 图1 一个简单语句的分析树 图1所示是一个简单语句的层级结构,把语句表示为树结构可以让我们用子树来分析句子的组成部分. 图2 ((7+3)?(5?2))的分析树 我们也可以把数学表达式如((7+3)?(5?2))表示为分析树,如图2.此前我们研究过完全括号表达式,这个表达式表达了什么呢?我们知道乘法的优先级比加减要高,但因为括号的关系,在做乘法之

python数据结构与算法 36 树的基本概念

树 学习目标 理解什么是树及使用方法 学会使用树实现映射 用列表实现树 用类和引用实现树 用递归实现树 用堆实现优先队列 树的例子 前面我们学习过栈和队列这类线性数据结构,并且体验过递归,现在我们学习另一种通用数据结构,叫做树.树在计算机科学中应用广泛,象操作系统.图形学.数据库系统.网络等都要用到树.树和他们在自然界中的表哥--植物树--非常相似,树也有根,有分枝,有叶子.不同之处是,数据结构的树,根在顶上,而叶子在底部. 在开始学习之前,我们来研究几个普通的例子.第一个是生物学上的分级树.图

python数据结构与算法 37 树的实现

树的实现 记住上一节树的定义,在定义的基础上,我们用以下的函数创建并操作二叉树: BinaryTree() 创建一个二叉树实例 getLeftChild() 返回节点的左孩子 getRightChild() 返回节点的右孩子 setRootVal(val) 把val变量值赋给当前节点 getRootVal() 返回当前节点对象. insertLeft(val) 创建一个新二叉树作为当前节点的左孩子 insertRight(val) 创建一个新二叉树作为当前节点的右孩子. 实现树的关键点是合适的存

python数据结构与算法 34 归并排序

归并排序 在提高排序算法性能的方法中,有一类叫做分而治之.我们先研究其中第一种叫做归并排序.归并排序使用递归的方法,不停地把列表一分为二.如果列表是空或只有一个元素,那么就是排好序的(递归基点),如果列表有超过1个的元素,那么切分列表并对两个子列表递归使用归并排序.一旦这两个列表排序完成,称为"归并"的基本操作开始执行.归并是把两个有序列表合并成一个新的有序列表的过程.图10是我们熟悉的列表样例分解过程,图11是归并的过程. 图10  切分过程 图11  归并过程 以下是mergeSo

Python数据结构与算法--List和Dictionaries

Lists 当实现 list 的数据结构的时候Python 的设计者有很多的选择. 每一个选择都有可能影响着 list 操作执行的快慢. 当然他们也试图优化一些不常见的操作. 但是当权衡的时候,它们还是牺牲了不常用的操作的性能来成全常用功能. 本文地址:http://www.cnblogs.com/archimedes/p/python-datastruct-algorithm-list-dictionary.html,转载请注明源地址. 设计者有很多的选择,使他们实现list的数据结构.这些选

python数据结构与算法 35 快速排序

快速排序 快速排序也使用了分而治之的策略来提高性能,而且不需要额外的内存,但是这么做的代价就是,列表不是对半切分的,因而,性能上就有所下降. 快速排序选择一个数值,一般称为"轴点",虽然有很多选取轴点的方法,我们还是简单地把列表中第一个元素做为轴点了.轴点的作用是帮助把列表分为两个部分.列表完成后,轴点所在的位置叫做"切分点",从这一点上把列表分成两部分供后续调用. 图12所示,54将作为轴点.这个例子我们已经排过多次了,我们知道54在排好序后将处于现在31的位置上

python数据结构与算法 39 树的遍历

树的遍历 在学习完成树的基本结构以后,我们开始研究一些树的应用模式.访问树的全部节点,一般有三种模式,这些模式的不同之处,仅在于访问节点的顺序不同.我们把这种对节点的访问称为"遍历",这三种遍历模式叫做前序.中序和后序.下面我们对遍历模式作更仔细的定义,同时研究使用这延续模式的例子. 前序遍历 在前序遍历中,先访问根节点,然后用递归方式前序遍历它的左子树,最后递归方式前序遍历右子树. 中序遍历 在中序遍历中,先递归中序遍历左子树,然后访问根节点,最后递归中序遍历右子树. 后序遍历 在后

Python数据结构与算法--算法分析

在计算机科学中,算法分析(Analysis of algorithm)是分析执行一个给定算法需要消耗的计算资源数量(例如计算时间,存储器使用等)的过程.算法的效率或复杂度在理论上表示为一个函数.其定义域是输入数据的长度,值域通常是执行步骤数量(时间复杂度)或者存储器位置数量(空间复杂度).算法分析是计算复杂度理论的重要组成部分. 本文地址:http://www.cnblogs.com/archimedes/p/python-datastruct-algorithm-analysis.html,转

我的软考之路(七)——数据结构与算法(5)之查找

上篇博文我重点介绍了八大内部排序,这篇博文(数据结构与算法的最后一课)重点介绍查找,我们依旧沿用上篇博文的风格,先简单介绍,再以例子重点讲解. 下面我们开始今天的旅行,首先祝你旅行愉快,呵呵. 静态查找 若查找目的是为了查询某个特定的数据是否在表中或检索某个特定数据的各种属性,则此类查找表为静态查找表. 1.顺序查找 基本原理:从表一端开始逐个和关键字进行比较,若找到一个记录和给定值相等,则查找成功,反之失败.再简单点就是,一个一个的比大小,看看是否相等. 例子: 顺序查找更适合于顺序存储结构和