散列表与散列算法

散列表的英文叫“Hash Table”,我们平时也叫它“哈希表”或者“Hash 表”,散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。

通过一个示例学习散列思想

假如我们有 89 名选手参加学校运动会。为了方便记录成绩,每个选手胸前都会贴上自己的参赛号码。这 89 名选手的编号依次是 1 到 89。现在我们希望编程实现这样一个功能,通过编号快速找到对应的选手信息。你会怎么做呢?我们可以把这 89 名选手的信息放在数组里。编号为 1 的选手,我们放到数组中下标为 1 的位置;编号为 2 的选手,我们放到数组中下标为 2 的位置。以此类推,编号为 k 的选手放到数组中下标为 k 的位置。因为参赛编号跟数组下标一一对应,当我们需要查询参赛编号为 x 的选手的时候,我们只需要将下标为 x 的数组元素取出来就可以了,时间复杂度就是 O(1)。这样按照编号查找选手信息,效率是不是很高?

实际上,这个例子已经用到了散列的思想。在这个例子里,参赛编号是自然数,并且与数组的下标形成一一映射,所以利用数组支持根据下标随机访问的时候,时间复杂度是 O(1) 这一特性,就可以实现快速查找编号对应的选手信息。但是这个例子散列思想还不够明显,那我来改造一下这个例子。

假设校长说,参赛编号不能设置得这么简单,要加上年级、班级这些更详细的信息,所以我们把编号的规则稍微修改了一下,用 6 位数字来表示。比如 051167,其中,前两位 05 表示年级,中间两位 11 表示班级,最后两位还是原来的编号 1 到 89。这个时候我们该如何存储选手信息,才能够支持通过编号来快速查找选手信息呢?思路还是跟前面类似。尽管我们不能直接把编号作为数组下标,但我们可以截取参赛编号的后两位作为数组下标,来存取选手信息数据。当通过参赛编号查询选手信息的时候,我们用同样的方法,取参赛编号的后两位,作为数组下标,来读取数组中的数据。

这就是典型的散列思想。其中,参赛选手的编号我们叫作键(key)或者关键字。我们用它来标识一个选手。我们把参赛编号转化为数组下标的映射方法就叫作散列函数(或“Hash 函数”“哈希函数”),而散列函数计算得到的值就叫作散列值(或“Hash 值”“哈希值”)

散列函数

散列函数顾名思义首先它是一个函数,我们可以简单定义它为hash(key),key为元素的键值,hash(key)生成的值叫做散列值。

一个散列函数应该满足哪些条件:

  1. 散列函数计算的值必须为非负整数
  2. 如果 key1 === key2,那么hash(key1) === hash(key2)
  3. 如何 key1 !== key2, 那么hash(key1) !== hash(key2)

上述的第三情况属于理论上,因为真实情况下几乎不存在每个不同的key对应不同的散列值,散列冲突几乎是不可避免的。因此我们需要找到一些方法尽量来减少散列冲突,后面会讲述。

总结规律

散列表用的就是数组支持按照下标随机访问的时候,时间复杂度是 O(1) 的特性。我们通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。当我们按照键值查询元素时,我们用同样的散列函数,将键值转化数组下标,从对应的数组下标的位置取数据。

代码实现

/**

散列表冲突问题

在真实的情况下,要想找到一个不同的 key 对应的散列值都不一样的散列函数,几乎是不可能的。即便像业界著名的MD5、SHA、CRC等哈希算法,也无法完全避免这种散列冲突。而且,因为数组的存储空间有限,也会加大散列冲突的概率。所以我们几乎无法找到一个完美的无冲突的散列函数,即便能找到,付出的时间成本、计算成本也是很大的,所以针对散列冲突问题,我们需要通过其他途径来解决。

分离链接法

在散列表中,每个“桶(bucket)”或者“槽(slot)”会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中。

当插入的时候,我们只需要通过散列函数计算出对应的散列槽位,将其插入到对应链表中即可,所以插入的时间复杂度是 O(1)。当查找、删除一个元素时,我们同样通过散列函数计算出对应的槽,然后遍历链表查找或者删除。那查找或删除操作的时间复杂度是多少呢?实际上,这两个操作的时间复杂度跟链表的长度 k 成正比,也就是 O(k)。对于散列比较均匀的散列函数来说,理论上讲,k=n/m,其中 n 表示散列中数据的个数,m 表示散列表中“槽”的个数。

/**

参考资料

数据结构与算法之美

PS: 有兴趣的关注我的公众号

利用开放定址法实现散列表的创建、插入、删除、查找操作_快速入门数据结构:散列表(上)...相关推荐

  1. 利用开放定址法实现散列表的创建、插入、删除、查找操作_散列表和IO

    散列表(也叫哈希表) 直接寻址法 取关键字或关键字的某个线性函数值为散列地址.即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数).若其中H(ke ...

  2. (5)散列冲突处理:开放定址法

    前面我们讲了一些设计散列函数的方法,从前面的除留余数法的例子也可以看出,我们设计得再好的散列函数也不可能完全避免冲突,这就像我们再健康也只能尽量预防疾病,但却无法保证永远不得病一样,既然冲突不能避免, ...

  3. 散列表(开放定址法)

    散列表(开放定址法) 1.线性探测法 将具体的值输入到哈希函数中,映射出的具体的哈希表中的下标索引.当下标索引冲突时. 离散链表法:将重复了的值用链表的方式挂在对应索引的链表下. 线性探测法:一个位置 ...

  4. 对散列冲突的处理——开放定址法

    对散列冲突的处理--开放定址法 之前聊了聊用分离链接法解决散列冲突的问题,这次就来聊聊对散列冲突的另一种解决办法:开放定址法.开放定址法分为线性探测,平方探测,双散列三种方法. 开放定址法 分离链接法 ...

  5. 冲突处理方法----开放定址法

    1 前言 常用处理冲突的思路: 换个位置: 开放地址法 同一位置的冲突对象组织在一起:链地址法 2 开放定址法(Open Addressing) 一旦产生了冲突(该地址已有其它元素),就按某种规则去寻 ...

  6. PAT甲级1145 Hashing - Average Search Time:[C++题解]哈希表、哈希表开放寻址法、二次探测法、求平均查找次数

    文章目录 题目分析 题目链接 题目分析 来源:acwing 本题的分析见另一道PAT的题目:PAT甲级1078 Hashing:[C++题解]哈希表.哈希表开放寻址法.二次探测法链接的题目就是让建立h ...

  7. python list去重并删除某些元素_使用Python实现list(列表)中的重复元素删除,例如: X= [1,1,2,a,a,[1,2,3]] 去重后:X= 「1,2,a,[1,2...

    题目要求的实质是列表内部元素的去重,有两种思路:第一种,删除的思路,判断列表中的元素是否出现重复,如果有重复,删除重复出现的元素直到剩下最后一个:第二种,添加的思路,新建空列表,将新列表中不包含.原列 ...

  8. 双链表——双链表的定义及其基本操作(初始化、头插法尾插法建表、插入、查找、删除、判空等)

    文章目录 双链表的定义 双链表上的操作 初始化 插入操作 建立双链表 头插法建立双链表 尾插法建立双链表 遍历操作 求双链表的长度 查找操作 按值查找 按位查找 删除操作 判空操作 完整代码及实例 总 ...

  9. 利用for循环调用插入方法批量插入 一条失败_算法与数据结构(1):基础部分——以插入排序为例...

    本文将会以插入排序为例,介绍算法与数据结构的基础部分. 插入排序 排序可以说是整个算法中最为基础,最为重要的一部分,而插入排序正是排序算法中最简单的一种解决办法. 什么是排序问题? 输入:n个数的一个 ...

最新文章

  1. jmeter中文_JMeter安装配置
  2. python 按钮事件_从django vi中的按钮获取click事件
  3. 关于Android构建
  4. 有道云笔记到简书的迁移工具
  5. linux查看wifi信号命令_使用Nmcli命令从Linux终端连接WiFi
  6. 统计词语出现次数python_Python实战教程:如何统计序列中元素的出现频度
  7. UE4中Bebavior Tree中Delay及其后面代码失效的原因
  8. bz10451045: [HAOI2008] 糖果传递
  9. NO.59 禅道的获奖奖品
  10. 自动加载简单实现 __autoload()
  11. E: Could not get lock /var/lib/dpkg/lock(无法获得锁)
  12. cisco产品命名规则
  13. Keil破解过程中注册机被识别为病毒文件
  14. 移动节点的间接路由方式
  15. Epic安装不成功/启动失败“必要的先决条件安装失败“
  16. 智能家居雷声越来越大 雨点还是那么小
  17. qq邮箱发送邮件到163邮箱
  18. OpenCart模板主题安装教程
  19. 如何diy一款MATLAB进度条?
  20. 线元法输入曲线要素_UG编程建模环境曲线倒圆角的方法

热门文章

  1. 苹果留给 iOS 开发者的时间不多了:30 天内必须更新旧版本
  2. 西北大学研发猴脸识别技术;小米造车未立项;Linux Mint 警告用户安全意识落后 | 极客头条...
  3. 一文解锁加密算法的秘密
  4. 阿里动物园再添新丁,小蛮驴搞定物流最后三公里!
  5. 电磁感应理论之父,法拉第传奇
  6. 谷歌爆苹果 Image I/O 存重大漏洞,无辜用户躺枪
  7. 悲剧!他写了20000行代码,却连6岁孩子都比不过!
  8. Windows 10 再香,国内超一半用户「死守」停更的 Windows 7
  9. 华为发布全容器化 5G 核心网;余承东评小米 MIX Aphla 手机无实用价值;PHP 新版本更新 | 极客头条...
  10. Chrome 为何会成功?