Python 中的哈希表
Python 中的哈希表:对字典的理解
有没有想过,Python中的字典为什么这么高效稳定。原因是他是建立在hash表上。了解Python中的hash表有助于更好的理解Python,因为Python中字典无处不在。
hash 函数
哈希函数是一个可以将任意长度的数据块映射到固定长度的值,这个步骤称为hash,也就是散列。
hash 函数有三个主要的特征:
- 计算迅速:计算一个数据块的hash值非常快
- 确定性:相同用字符串会产生相同的hash值
- 结果固定长度:不管输入的是,一个字节还是十个字节,或者上万个字节,结果总是预先确定的长度。
另一个特征在hash函数中非常普遍,即他们是单方向的:通过函数实现后,原始数据丢失了,我们可以通过字符串得到一个hash值,但不能通过一个hash也就是散列得到原始的字符串(因为有对数据降维的方法会造成数据的丢失)。这种特性并不是对所有hash函数的强制性规定,但是当需要加密安全时,这种性质还是挺好用的。
一些比较受欢迎的算法包括:MD5、SHA-1、SHA-2,NTLM.
关于hash的一些使用方法
很多东西都依赖hash,hash表就是其中一例,另一些用法是出于加密和的原因
一个具体的例子就是当你尝试从网上下载开源软件时。通常你都会发现一个关联文件,这个关联文件就是这个文件签名。这个签名仅仅是源文件的散列值它非常有用,你为你可以自己通过计算下载好的文件的散列值并与网站上提供的签名进行对比,这样就可以确认你自己下载的文件没有损坏。
另一种用法是存储用户的密码。你有没有问过你自己,当你忘掉了一个网站的登录密码的时候,你还想从这个网站上恢复登录,它只会让你重新确定一个新的登录密码而不是给你原来你选择的密码,这是因为网站并不会储存你完整的密码,而是你密码的hash值。
这么做是出于安全因素,因为如果黑客搞到了数据库的权限,他们不会知道你真实的密码,而是仅仅得到你密码的哈希值,又因为哈希函数是单向的,他们根本不可能从哈希值得到你的密码
Python 里的hash()函数
Python 中含有内置的函数去给对象生成哈希值,也就是hash()函数,这个函数将一个对象作为输入,返回一个整数的hash值。
内部的,这个函数涉及到.\__hash\__()这个输入对象的方法,所以呢,如果你想使你的自定义类可哈希化,你需要做的是实现.\__hash__()这个方法返回出一个整数,这个整数是基于你的对象的内部状态决定的。
先开始一些基本的小例子,先对数值进行散列
>>> hash(1)
1
>>> hash(10)
10
>>> hash(10.00)
10
>>> hash(10.01)
230584300921368586
>>> hash(-10.01)
-230584300921368586
如果你好奇为什么这些hash值看起来有不同的长度,请记住在Python中hash()函数返回的是整数对象,他们都会在标准的64位Python解释器中通过24字节呈现。
正如你可以看到的,整数的哈希值默认的就是它本身,不管你哈希的数据类型是什么,所以整数1和浮点数1.0哈希值都是1.
这个有什么特殊的么,这个展示了你之前学到的知识,也就是hash函数经常是单向的函数,如果两个不同的对象具有相同的hash值,根本不可能做反向工程,也就是从hash值返回到原始的对象,这也就使得被hash的原始数据类型的信息被丢失。
另几个有趣的可以关注的hash事情是,小数的散列值不同于它本身,负数具有负的哈希值。还有一点,就是如果两个对象具有相同的哈希值,称为哈希碰撞。
哈希一个字符串不同于对数值进行哈希。
>>> hash("Bad Behaviour")
7164800052134507161
DOS攻击(DOS代表拒绝服务)是指攻击者故意耗尽计算机系统的资源,使系统不再能够向客户端提供服务的攻击。在Scott Crosby演示的这个攻击的具体案例中,攻击可能会使目标系统充斥大量的数据,这些数据的哈希冲突导致目标系统使用更多的计算能力来解决冲突。
Python中可以hash的数据类型
在Python中,仅仅只有不可变数据类型可以被hash,然而每个自定义的对象在Python中都可以被hash,默认的他们的hash值是由他们的id派生的。也就意味着,同一个类的两个不同实例,默认的是得到不同的hash值
>>> class Car():
... velocity = 0
... direction = 0
... damage = 0
...
>>> first_car = Car()
>>> second_car = Car()
>>> hash(first_car)
274643597
>>> hash(second_car)
274643604
哈希表
现在你知道了什么是哈希函数,现在可以检测哈希表,哈希表是一个数据结构可以储存一堆键值对。
在哈希表中,键值对的所有建必须是可以哈希的,因为存储的对是通过使用其键的散列索引的。哈希表十分有用,Hash tables are very useful because the average number of instructions that are necessary to lookup an element of the table is independent of the number of elements stored in the table itself.哈希表非常有用,因为查找表中某个元素所需的平均指令数量与表中存储的元素数量无关,这就表明了不管你的表增长到成百上千次,查找特定元素的速度不会受到影响。
哈希表通常是通过创建可变数量的存储桶来实现的,这些存储桶将包含您的数据,并通过哈希它们的键对这些数据进行索引。键的散列值将确定用于特定数据段的正确存储桶。
import pprint
class Hashtable:
def __init__(self, elements):
self.bucket_size = len(elements)
self.buckets = [[] for i in range(self.bucket_size)]
self._assign_buckets(elements)
def _assign_buckets(self, elements):
for key, value in elements:
hashed_value = hash(key)
index = hashed_value % self.bucket_size
self.buckets[index].append((key, value))
def get_value(self, input_key):
hashed_value = hash(input_key)
index = hashed_value % self.bucket_size
bucket = self.buckets[index]
for key, value in bucket:
if key == input_key:
return(value)
return None
def __str__(self):
return pprint.pformat(self.buckets) # here pformat is used to return a printable representation of the object
if __name__ == "__main__":
capitals = [
('France', 'Paris'),
('United States', 'Washington D.C.'),
('Italy', 'Rome'),
('Canada', 'Ottawa')
]
hashtable = Hashtable(capitals)
print(hashtable)
print(f"The capital of Italy is {hashtable.get_value('Italy')}")
Moreover, the more you increase the number of buckets you will handle, the more space you will waste. To test this you can simply change the bucket size of your previous example using a number of buckets that is two times the length of the input list:
此外,处理的桶数增加越多,浪费的空间就越多。要测试这一点,只需使用输入列表长度的两倍的桶数来更改上一个示例的桶大小
两个散列值发生碰撞,将会存储到同一个桶中,因为冲突不可避免,实现一个哈希表就得有一个解决冲突的方法。
通常在哈希表解决冲突的常用策略是:
- open addressing 开放寻址法
- separate chaining 链地址法
连地址法是您在上面的示例中已经实现的,它由使用另一个数据结构在同一个bucket中创建一个值链组成。在那个示例中,您使用了一个嵌套列表,当在超额占用的bucket中查找特定值时,必须对该列表进行完全扫描。
在开放寻址策略中,如果您应该使用的bucket是忙碌的,那么您只需继续搜索要使用的新bucket。要实现这个解决方案,您需要对为新元素分配bucket的方式和检索键值的方式进行一些更改。从assign buckets()函数开始,您必须使用默认值初始化您的bucket,并且如果您应该使用的bucket已经被占用,则继续寻找空的bucket
Dictionaries in Python are built using hash tables and the **open addressing** collision resolution method.
Python 中的哈希表的更多相关文章
- 【转】实习小记-python中可哈希对象是个啥?what is hashable object in python?
[转]实习小记-python中可哈希对象是个啥?what is hashable object in python? 废话不多说直接祭上python3.3x的文档:(原文链接) object.__ha ...
- [PHP内核探索]PHP中的哈希表
在PHP内核中,其中一个很重要的数据结构就是HashTable.我们常用的数组,在内核中就是用HashTable来实现.那么,PHP的HashTable是怎么实现的呢?最近在看HashTable的数据 ...
- 实习小记-python中不可哈希对象设置为可哈希对象
在这篇之前,我又专门翻译过官方python3.3的可哈希对象文档,大家可以先参考一下: 实习小记-python中可哈希对象是个啥?what is hashable object in python? ...
- Delphi 中的哈希表: THashedStringList
转自万一博客 Delphi 中的哈希表: THashedStringList unit Unit1; interface uses Windows, Messages, SysUtils, Var ...
- 实习小记-python中可哈希对象是个啥?what is hashable object in python?
废话不多说直接祭上python3.3x的文档:(原文链接) object.__hash__(self) Called by built-in function hash() and for opera ...
- python数据结构之哈希表
哈希表(Hash table) 众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是Has ...
- 数据结构与算法Python版 熟悉哈希表,了解Python字典底层实现
Hash Table 散列表(hash table)也被称为哈希表,它是一种根据键(key)来存储值(value)的特殊线性结构. 常用于迅速的无序单点查找,其查找速度可达到常数级别的O(1). 散列 ...
- OVS 中的哈希表: shash
shash出现在OVS的代码中,定义如下: struct hmap_node { size_t hash; struct hmap_node * next; }; struct ...
- Freemarker 中的哈希表(Map)和序列(List)
freemarlker中的容器类型有: 哈希表:是实现了TemplateHashModel或者TemplateHashModelEx接口的java对象,经常使用的实现类是SimpleHash,该类实现 ...
随机推荐
- MySQL慢查询开启、日志分析(转)
说明 Mysql的查询讯日志是Mysql提供的一种日志记录,它用来记录在Mysql中响应时间超过阈值的语句 具体指运行时间超过long_query_time值得SQL,则会被记录到慢查询日志中.lon ...
- mysql mybatis Date java时间和写入数据库时间不符差一秒问题
1,java的数据库实体定义 private Timestamp createTime:2,非常重要!ddl语句建表字段的单位 datetime要手动设置保留3位毫秒数,不然就四舍五入了! ALTER ...
- 利用CSS3实现div页面淡入动画特效
利用CSS3实现页面淡入动画特效 摘要 利用CSS3动画属性"@keyframes "可实现一些动态特效,具体语法和参数可以网上自行学习.这篇文章主要是实践应用一下这个动画属性 ...
- 寻找cmd的管理员运行
(快捷键----打开"cmd"----"win+R") 在进行环境配置测试中,有些是需要将cmd用管理员方式来运行才可以,但是,当你在"开始" ...
- 在FL Studio中如何做出渐入的人声效果
当我们在拿到一段人声并想把它加入歌曲中时,如果我们发现人声没有渐入的效果,直接加入到歌曲里出现会变得很突兀的话,我们就需要用到这篇文章所介绍的方法,给人声加上一个渐入的效果. 1. 找到我们需要处理的 ...
- 和功能相近的虚拟机软件相比,CrossOver的产品优势有哪些?
很多用户其实并不喜欢虚拟机软件,他们只是想用回熟悉的Windows应用程序,因为苹果系统与许多软件并不兼容.无奈之下,他们只能安装虚拟机软件.可是虚拟机软件大多比较笨重并且也相对复杂一些,在后期维护上 ...
- python中操作数据库
python中要操作数据库,要使用该数据库在python中对应的驱动库,本文介绍python操作mysql数据库 1.首先安装pymysql 2.导入库 3.建立连接 4.建立游标 5.发起请求 6. ...
- web自动化 模拟鼠标、键盘操作
一.鼠标操作 1.1鼠标的悬停操作,move_to_element from selenium import webdriver from selenium.webdriver.common.acti ...
- 在iOS中使用ZBar扫描二维码和条形码
最近做了个外包项目,里面用到了二维码扫描和微信支付!之前比较熟悉的是ZXing,但是在Xcode7.1里面发现竟然莫名的不支持,木有办法,从网上查了一下还有一种支持二维码扫描的东西,没错就是接下来我要 ...
- 【干货】linux使用nginx一个80端口部署多个项目(spring boot、vue、nuxt、微信小程序)
本人只有一个阿里云的ip和一个已经解析过的域名,然后想用80端口部署多个项目,比如输入: www.a.com和www.b.com与www.c.com就能访问不同项目,而不用输入不同端口号区分. 1.这 ...