【深度解析算法】散列表 上

8 散列表

如果所有的键都是小整数,我们可以用一个数组来实现无序的符号表,将键作为数组的索引而数组中键i处储存的就是它对应的值。这样我们就可以快速访问任意键的值。在本节中我们将要学习散列表。它是这种简易方法的扩展并能够处理更加复杂的类型的键。我们需要用算术操作将键转化为数组的索引来访问数组中中的键值使用散列的查找算法分为两步。第一步是用散列函数将被查找的键转化为数组的一个索引。 理想情况下,不同的键都能转化为不同的索引值。当然, 这只是理想情况,所以我们需要面对两个或者多个键都会散列到相同的索引值的情况。因此,散列查找的第二步就是一个处理碰撞冲突的过程。在描述了多种散列函数的计算后,我们会学习两种解决碰撞的方法:拉链法和线性探测法。

散列表是算法在时间和空间上作出权衡的经典例子。如果没有内存限制,我们可以直接将键作为(可能是一个超大的)数组的索引,那么所有查找操作只需要访问内存一次即可完成。 但这种理想情况不会经常出现,因为当键很多要的内存太大。另一方面,如果没有时间限制,我们可以使用无序数组并进行顺序查找,这样就只需要很少的内存。而散列表则使用了适度的空间和时间并在这两个极端之间找到了一种平衡。 事实上,我们不必重写代码,只需要调整散列算法的参数就可以在空间和时间之间作出取舍。我们会使用概率论的经典结论来帮助我们选择适当的参数。概率论是数学分析的重大成果。虽然它不在本书的讨论范围之内,但我们将要学习的散列算法利用了这些知识,这些算法虽然简单但应用广泛。使用散列表,你可以实现在一般应用中拥有(均摊后)常数级别的查找和插入操作的符号表。这使得它在很多情况下成为实现简单符号表的最佳选择。

8.1散列函数

我们面对的第一个问题就是散列函数的计算,这个过程会将键转化为数组的索引。如果我们有一个能够保存M个键值对的数组,那么我们就需要一个能够将任 意键转化为该数组范围内的索引([0,M-1]范围内的整数)的散列函数。我们要找的散列函数应该易于计算并且能够均匀分布所有的键,即对于任意键,0到M-1之间的每个整数都有相等的可能性与之对应(与键无关)。这个要求似乎有些难以理解。那么要理解散列,就首先要仔细思考如何去实现这样一个丽数。

散列函数和键的类型有关。严格地说,对于每种类型的键都我们都需要一个与之对应的散列函数。如果键是一个数,比如社会保险号,我们就可以直接使用这个数:如果键是一个字符串, 比如一个人的名字, 我们就需要将这个字符串转化为一个数: 如果健含有多个部分,比如邮件地址,我们需要用某种方法将这些部分结合起来。对于许多常见类型的键,我们可以利用Java提供的默认实现。我们会简略讨论多种数据类型的散列函数。你应该看看它们是如何实现的,因为你也需要为自定义的类型实现散列函数。

8.1.1 典型的例子

假设在我们的应用中,键是美国的社会保险号。一个社会保险号含有9位数字并被分为三个部分,例2如23.45-6789。 第一组数字表示该号码答发的地区(例如,第一键散列值 做列值组号码为035的社会保险号来自罗得岛州,214则来自马里兰州),另两组数字表示个人身份。社会保险号共有10亿(102)个,但假设我们的应用程序只需要处理几百个,我们可以使用一个大小M= 1000的散列表。散列函数的一种实现方法是使用键(社会保险号)中的三个数字。用第三组中的三个数字似乎比用第一-组中的三个数字更好(因为我们的客户不太可能完全平均地分布在各个地区),但下面会讲到,更好的方法是用所有9个数字得到一个整数,然后再考虑整数的散列函数。

8.1.2 正整数

将整数散列最常用方法是除留余鼓法。我们选择大小为素数M的数组,对于任意正整数k,计算k除以M的余数。这个函数的计算非常容易(在Java中为k%M)并能够有效地将键散布在0到M-I的范围内。如果M不是素数,我们可能无法利用键中包含的所有信息,这可能导致我们无法均匀地散列散列值。例如,如果键是十进制数而M为10’,那么我们只能利用键的后k位,这可能会产生一些问题。 举个简单的例子,假设键为电话号码的区号且M = 100。由于历史原因,美国的大部分区号中间位都是0或者1,因此这种方法会将大量的键散列为小于20的索引,但如果使用素数,散列值的分布显然会更好(一个离100 更远的素数会更好)。与之类似,互联网中使用的IP地址也不是随机的,所以如果我们想用除留余数法将其散列就需要用素数(2的幂除外)大小的数组。

8.1.3 浮点数

如果键是0到 1之间的实数,我们可以将它乘以M并四舍五人得到一个0至M-1之间的索引值。尽管这个方法很容易理解,但它是有缺陷的,因为这种情况下键的高位起的作用更大,最低位对散列的结果没有影响。修正这个问题的办法是将键表示为二进制数然后再使用除留余数法( Java就是这么做的)。

8.1.4 字符串

除留余数法也可以处理较长的键,例如字符串,我们只需将它们当作大整数即可。例如,下面的代码就能够用除留余数法计算String S的散列值:

Java的charAt()函数能够返回一个 char值,即一个非负16位整数。如果R比任何字符的值都大,这种计算相当于将字符串当作一个N位的R进制值,将它除以M并取余。一种叫Homner方法的经典算法用N次乘法、加法和取余来计算-个字符串的散列值。只要R足够小,不造成溢出,那么结果就能够如我们所愿,落在0至M-1之内。使用一个较小的素数,例如31,可以保证字符串中的所有字符都能发挥作用。Java 的String的默认实现使用了一个类似的方法。

散列字符串键
int hash = 0;for(int i = 0; i < s.length; i++){hash= (R + hash + s.charAt(i)) % M;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/767769.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常见技术难点及方案

1. 分布式锁 1.1 难点 1.1.1 锁延期 同一时间内不允许多个客户端同时获得锁&#xff1b; 1.1.2 防止死锁 需要确保在任何故障场景下&#xff0c;都不会出现死锁&#xff1b; 1.2.3 可重入 特殊的锁机制&#xff0c;它允许同一个线程多次获取同一个锁而不会被阻塞。 1.2…

Web前端Html的表单

表单的关键字&#xff1a; form标签表示一个表单区域 action“后端地址” method“提交数据方式:get/post” input 单行输入框 type“text” 文本 name“定义名称 名字自定义” 向后端提交的键 readonly“readonly” 只读&#xff0c;不可修改&#xff0c;但是可以提交 disab…

C语言学习-day22-函数递归1

程序调用自身的编程技巧被称为递归。举个例子&#xff1a; int main() { printf("hehe\n"); main(); return 0; } 比如这种&#xff0c;自己调用自己后每次都打印一个hehe。 递归的核心思考方式在于&#xff1a;大事化小。 做个练习&#xff1a;接收一个整型值&a…

鸿蒙Harmony应用开发—ArkTS-类型定义

说明&#xff1a; 本模块首批接口从API version 7开始支持&#xff0c;后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 Resource 资源引用类型&#xff0c;用于设置组件属性的值。 可以通过$r或者$rawfile创建Resource类型对象&#xff0c;不可以修改Res…

【S056】Clause46--XGMII接口摘要

文章目录 XGMII数据与lane的对应关系是什么&#xff1f;XGMII上的数据流格式是什么&#xff1f;如何保证0xFB每次都在Lane0&#xff1f;方法一&#xff1a;方法二&#xff1a; Link Fault信号 XGMII数据与lane的对应关系是什么&#xff1f; XGMII上的数据流格式是什么&#xff…

GDC期间LayaAir启动全球化战略

3 月 18 日至 3 月 22 日&#xff0c;一年一度的游戏开发者大会&#xff08;GDC&#xff09;在美国旧金山举行。在此期间&#xff0c;Layabox宣布LayaAir引擎启动全球扩张战略&#xff0c;这标志着引擎将步入快速发展的新阶段。此举旨在利用公司先进的3D引擎技术&#xff0c;将…

Linux之git

一、什么叫做版本控制 版本控制&#xff08;Revision control&#xff09;是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史&#xff0c;方便查看更改历史记录&#xff0c;备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理多人协同开发项目的技…

Affiliate Stores: 建立营销联盟商店的详细教程- US Domain Center主机

第一步&#xff1a;了解营销联盟商店 营销联盟商店是一种电子商务模式&#xff0c;您可以在其中通过推广其他企业的产品或服务来赚取佣金。您在自己的网站上展示其他企业的产品&#xff0c;并在买家购买时获得佣金。通过 WooCommerce 平台&#xff0c;您可以轻松创建一个营销联…

学习总结!

java目前学习到了数组部分 广搜&#xff0c;在开始的时候把#处理一下会好做很多&#xff0c;遇到上下两层都是# 的&#xff0c;就把上下两层的这个位置都弄成墙就行。还有遇到 一层是#&#xff0c;一层是墙的。也直接把俩都弄城墙就行&#xff0c;省的要判断他撞死&#xff0c;…

vue2的v-model不更新

场景 动态生成组件时&#xff0c;动态为表单添加属性&#xff0c;同时使用v-model以数组形式访问表单属性。通过监听表单对象&#xff0c;发现并未实施更新。 原因 vue2无法监听数组索引一系列操作&#xff0c;从而不能及时响应。vue2是通过Object.definePropertys实现响应式的…

部署mysql,前端,后端

部署mysql docker pull mysql 从镜像源中拉取镜像。 创建mysql容器 docker run -d \--name mysql_container \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT_PASSWORD123 \--restartalways \-v /opt/mysql:/var/lib/mysql \mysql -d后台运行&#xff0c;--name指定容器…

【JavaScript】JavaScript 程序流程控制 ⑤ ( 嵌套 for 循环 | 嵌套 for 循环概念 | 嵌套 for 循环语法结构 )

文章目录 一、嵌套 for 循环1、嵌套 for 循环概念2、嵌套 for 循环语法结构 二、嵌套 for 循环案例1、打印三角形2、打印乘法表 一、嵌套 for 循环 1、嵌套 for 循环概念 嵌套 for 循环 是一个 嵌套的 循环结构 , 其中一个 for 循环 位于另一个 for 循环的内部 , 分别是 外层 f…

计算机网络实验——学习记录二(HTTP协议)

1. Linux主机上连接互联网的网络接口是&#xff1a;ens33。 2. 在显示过滤器&#xff08;Filter&#xff09;中输入“ http.host www.zzu.edu.cn”&#xff0c;筛选出HTTP协议报文首部行中包含“ Host&#xff1a;www.zzu.edu.cn”的报文&#xff08;目的地址是Web服务器的报…

学习或复习电路的game推荐:nandgame(NAND与非门游戏)、Turing_Complete(图灵完备)

https://www.nandgame.com/ 免费 https://store.steampowered.com/app/1444480/Turing_Complete/ 收费&#xff0c;70元。据说可以导出 Verilog &#xff01;

十.pandas方法总结Numpy

目录 十.pandas方法总结 1.索引切片 2.数据排序 3.数据统计 Pandas数据计算 4.数据查看 5.数据清洗 6-数据分组 查看分组结果 7-处理第三方数据 csv文件操作 Excel文件操作 Excel文件读取read_excel Excel文件写入 to_excel() SQL操作 mysql读取 数据保存 pa…

Ubuntu 未能识别较新型号 Nvidia 显卡案例分析

&#xff08;首发地址&#xff1a;学习日记 https://www.learndiary.com/2024/03/unknown-nvidia-card-in-ubuntu/ &#xff09; 大家好&#xff0c;我是在淘宝“学习日记小店”做 Linux 服务的 learndiary。本文分享两个关于 Ubuntu 操作系统未能正确识别新型 NVIDIA 显卡型号…

代码随想录算法训练营第二十五天| LeetCode216. 组合III、LeetCode17.电话号码的字母组合

#LeetCode 216. Combination III #LeetCode 216. 视频讲解&#xff1a;和组合问题有啥区别&#xff1f;回溯算法如何剪枝&#xff1f;| LeetCode&#xff1a;216.组合总和III_哔哩哔哩_bilibili 如果做了77 题后&#xff0c;这个题目可以用相似的思路。回溯三部曲&#xff1a; …

c++和c语言的区别实例

C和C语言在程序设计领域内具有深远的影响&#xff0c;它们不仅丰富了编程的世界&#xff0c;也为软件开发人员提供了强大的工具。虽然C是在C语言的基础上发展起来的&#xff0c;但两者之间存在着一些关键的区别。为了更深入地理解这些不同&#xff0c;本文将从多个维度探讨C和C…

数据结构——双向链表(C语言版)

上一章&#xff1a;数据结构——单向链表&#xff08;C语言版&#xff09;-CSDN博客 目录 什么是双向链表&#xff1f; 双向链表的节点结构 双向链表的基本操作 完整的双向链表示例 总结 什么是双向链表&#xff1f; 双向链表是一种常见的数据结构&#xff0c;它由一系列节…

深度学习pytorch——可视化visdom(持续更新)

安装可看&#xff1a;e: Error while finding module specification for ‘visdom.server‘ (ModuleNotFoundError: No module name-CSDN博客 在命令行窗口使用python -m visdom.server&#xff0c;会出现一个web地址&#xff0c;在浏览器中访问&#xff0c;即可看见在python中…