前几天发了一篇名为 存储 dict 的元素前是计算 key 的 hash 值? 的文章,因缺乏相关的背景知识,导致得出了不正确的推论。
那篇文章的推论是

在不考虑 hash 冲突的情况下, 'a' 所在内存地址的 hash 值与 'b' 所在内存地址的 hash 值之间的差值 和 'a' 的内存地址与 'b' 的内存地址之间的差值 相等,也就是说以下的等式成立才对

hash(id('a')) - hash(id('b')) == id('a') - id('b')

简单说是:存储 dict 的元素前计算的是 key 所在内存地址的 hash 值
上面的等式是成立的

>>> hash(id('a')) - hash(id('b')) == id('a') - id('b')
True
>>> id('a') - id('b')
1680
>>> hash(id('a')) - hash(id('b'))
1680

但是需要纠正说明的是,我上面的那个推论是错的!

等式成立的原因

这里先说上面的等式为什么成立,因为整数的 hash 值是其本身

>>> a
1234567
>>> hash(a)
1234567

又因为内存地址是个整数,所以内存地址的 hash 值也是其本身,即和内存地址一样的值

>>> my_dict = {'a': 'apple', 'b': 'banana'}
>>> hash(id('a')) == id('a')
True
>>> id('a')
2673717403464
>>> hash(id('a'))
2673717403464

这就是为什么这个等式成立

hash(id('a')) - hash(id('b')) == id('a') - id('b')

推论错误的原因

如果两个值不同,那么它们的内存地址也不同,这是正确的,但我错误的认为如果值相同,那么内存地址也相同。下面是一个具有相同值不同内存地址的例子

>>> c = 'a-c'
>>> d = 'a-c'
>>> id(c) == id(d)
False
>>> id(c)
2673720167592
>>> id(d)
2673720167704

注:上面的 cd 虽然值是相同的,但它们不是同一个对象,所以内存地址不一样

回到那个错误的推论:

存储 dict 的元素前计算的是 key 所在内存地址的 hash 值

该推论成立的前提之一是:相同的 key 值的内存地址必须相同,但事实是像上面的例子一样,相同的 key 值可以拥有不同的内存地址

假设该推论成立的话,就会导致 dict 中出现两个相同的 key 值,但事实不是这样的,即便内存地址不同,只要值相同就不可以同时作为 dict 的 key,后者会覆盖前者。

>>> c
'a-c'
>>> d
'a-c'
>>> {c: 0, d: 1}
{'a-c': 1}

因为相同的 key 具有相同的 hash 值

>>> hash(c) == hash(d)
True
>>> hash(c)
-8124728931706162487
>>> hash(d)
-8124728931706162487

存储 dict 的元素前是计算 key 的 hash 值

首先了解下关于 key 与其 hash 值之间的几点事实:

  1. 相同的 key 肯定具有相同的 hash 值;

    应该不用解释,这是 hash 算法决定的;

  2. 不同的 key 也可能具有相同的 hash 值;

    因为 hash 算法会将任何长度的数据转换成一个固定长度的字符串(int 对象除外),所以可能生成的 hash 值的数量是有限的,而可用来计算 hash 值的数据量理论上是无穷的,这就造成两个数据的 hash 值可能相同

  3. 具有相同 hash 值的 key 不一定相同;

    原因正是因为不同的 key 可以具有相同的 hash 值

  4. 具有不同 hash 值的 key 肯定不同

    原因正是因为相同的 key 具有相同的 hash 值;

dict 是基于哈希表的数据结构,哈希表是一块连续的内存空间(数组),因为所存储的 key-value 散落在不同的位置上,key-value 之间存在大量的空白空间是很常见的,所以哈希表又称散列表。
dict 本质就是一个能利用散列函数将 key 转化为索引的数组(散列函数+数组),散列函数的功能之一是将 key 值转换为数组索引(dict 的 key 具有唯一性的本质是数组索引的唯一性)。在转换的过程中,需要对 key 进行 hash 值计算,计算 hash 值的目的是为了确定 key 应该存储在数组中的哪个位置(索引),即定位,而不是判断两个 key 是否相同。因为通过比较 hash 值是无法判断两个 key 是否相同的(参考前面的第 3 点事实),所以当 hash 值相同时,会定位到相同的表元(索引对应的元素),该表元里的 key 是否与计算的 key 相等还需要进一步判断。

反正存储 dict 的元素前还是计算 key 的 hash 值,但这只是散列函数中的其中一个过程或步骤。

  • 手动汉化 PyCharm 的过程
  • 模拟登陆Github
  • 字符图像识别——数字字母混合
  • 爬取猫眼实时票房数据

纠正存储 dict 的元素前是计算 key 的 hash 值?相关推荐

  1. 存储 dict 的元素前是计算 key 的 hash 值?

    dict 的高性能与其存储方式是分不开的,我们知道 dict 的存储是基于哈希表(又称散列表),需要计算 hash 值,那么是计算谁的 hash 值呢?是像别人说的:存储 dict 元素前计算 key ...

  2. HashMap 计算key的hash值方法hash()

    static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >&g ...

  3. Linux和Windows下计算文件的Hash值

    Linux和Windows下计算文件的Hash值 MD和SHA简介 MD SHA MD5 SHA1标识文件唯一性 Linux Windows 不需要下载工具,也不需要写代码. MD和SHA简介 MD ...

  4. 【转】Java计算文件的hash值

    原文地址:http://blog.csdn.net/qq_25646191/article/details/78863110 如何知道一个文件是否改变了呢?当然是用比较文件hash值的方法,文件has ...

  5. Java计算文件的hash值

    如何知道一个文件是否改变了呢?当然是用比较文件hash值的方法,文件hash又叫文件签名,文件中哪怕一个bit位被改变了,文件hash就会不同. 比较常用的文件hash算法有MD5和SHA-1. 我用 ...

  6. 关于计算ico文件hash值脚本

    如何利用ico文件查找出网站的真实IP地址,分享一个计算网站ico文件hash值的工具(python2和python3双版本代码) python2的工具脚本代码 python3的工具脚本代码 pyth ...

  7. 计算文件的hash值方法 | 使用powershell 以及 使用python

    使用windows的powershell进行get-filehash命令计算 使用python的hashlib库,进行文件的hash运算

  8. python字典怎么增加元素_Python字典(dict)增加元素

    Python字典(dict)增加元素 在 如果 key 不存在,那么会将 key 添加进字典,并将该 key 的值设置为 value. 字典增加元素详解 语法 dict[key] = value 参数 ...

  9. Java中的Hash值到底是怎么计算的

    最近被提及Java中HashMap的一些实现及哈希冲突等,不知不觉就想到哈希值到底是怎么计算出来的,正文如下. 结论: 对于String.Integer等类复写了Object中的hashCode方法的 ...

最新文章

  1. python numpy 欧氏距离
  2. Golang中的自动伸缩和自防御设计
  3. oracle插入未调用并行,oracle并行之概念篇
  4. 由SpringMVC中RequetContextListener说起
  5. Python中的顺序表介绍
  6. linux换源_Win10子系统(linux)安装及迁移
  7. 数据结构与算法——贪心算法汇总整理
  8. WIN 11 华为secoClient 客户端 提示“提示用户与对方建立连接超时,配置错误或网络故障”
  9. Unity 工具 之 XChart UGUI 表格工具,轻松简单的帮你实现需要的数据图表形式,建议 Mark 一下
  10. CuteFTP下载大文件时报错
  11. java实现多表代替密码(维吉尼亚密码)
  12. android开发之UI
  13. 【C++笔试强训】第三天
  14. 舆情传播的全过程如何监控监测?
  15. Unity 之 关于停止协程的五种方式解析
  16. 初识MacBook pro 2016--安装系统(恢复系统)
  17. 食品品牌如何做好消费需求洞察直抵消费者心智
  18. Android 代码命名规范 -- 提高代码可以读性
  19. C语言实现等效旋转矢量与三维矢量相乘
  20. Web应用接入Github登录

热门文章

  1. 前途,路应该怎么走?
  2. 最近要用C#实现用免费smtp服务器(GMail)发邮件,贴段整理好的代码
  3. PgSQL · 最佳实践 · 从 MaxCompute (ODPS) 迁移数据到 HybridDB
  4. Codeforces 509C Sums of Digits
  5. Android 学习笔记【基础扫盲篇】
  6. python工具用什么语言_Python中一些自然语言工具的使用的入门教程
  7. 安卓系统怎么安装软件_「软件」怎么在虚拟机里安装系统
  8. CoreAnimation-CALayer简述
  9. Resumable.js - 基于HTML5 File API的可断点续传的文件上传插件
  10. View DrawingCache的理解