Python内部很地方都使用着dict这种结构,在对象属性__dict__就是一个字典,所以对其效率要求很高。

dict采用了哈希表,最低能在 O(1)时间内完成搜索。同样的java的HashMap也是采用了哈希表实现,不同是dict在发生哈希冲突的时候采用了开放寻址法,而HashMap采用了链接法

开放寻址法

优点

  1. 记录更容易进行序列化(serialize)操作
  2. 如果记录总数可以预知,可以创建完美哈希函数,此时处理数据的效率是非常高的

缺点

  1. 存储记录的数目不能超过桶数组的长度,如果超过就需要扩容,而扩容会导致某次操作的时间成本飙升,这在实时或者交互式应用中可能会是一个严重的缺陷
  2. 使用探测序列,有可能其计算的时间成本过高,导致哈希表的处理性能降低
  3. 由于记录是存放在桶数组中的,而桶数组必然存在空槽,所以当记录本身尺寸(size)很大并且记录总数规模很大时,空槽占用的空间会导致明显的内存浪费
  4. 删除记录时,比较麻烦。比如需要删除记录a,记录b是在a之后插入桶数组的,但是和记录a有冲突,是通过探测序列再次跳转找到的地址,所以如果直接删除a,a的位置变为空槽,而空槽是查询记录失败的终止条件,这样会导致记录b在a的位置重新插入数据前不可见,所以不能直接删除a,而是设置删除标记。这就需要额外的空间和操作。

想要自己实现一个dict可以继承 collection 的 UserDict,里面已经封装了常用的方法。
下面是我根据自己的理解去用python实现的字典,简化了很的功能,比如对象缓冲池、String哈希的优化等等,如果有错误的或者更好的实现方式请指出。因为python没有纯粹的数组结构,所以数组也是借用list实现的.

#python3.6
from collections import namedtupleclass SimpleArray(object):#简单的数组类实现def __init__(self, mix):self.container = [None for i in range(mix)]def __len__(self):return len(self.container)def __setitem__(self, key, value):return self.container.__setitem__(key,value)def __getitem__(self, item):return self.container.__getitem__(item)def __delitem__(self, key):return self.container.__setitem__(key, None)def __str__(self):return str(self.container)class SimpleDict(object):#简单的字典类实现Init_length = 8 # 初始化的大小Load_factor = 2/3 # 扩容因子def __init__(self):self._array_len = SimpleDict.Init_lengthself._array = SimpleArray(self._array_len)self._used = 0self.dictObj = namedtuple("dictObj","key value") # 这里其实可以用数组也可以的,namedtuple是为了让代码更可读def __getitem__(self, item):key = self._hash(item)dictObj = self._array[key]if dictObj is not None and dictObj.key == item:return dictObj.valueelse:for new_key in self._second_hash(key):if self._array[new_key] is not None and item == self._array[new_key].key:return self._array[new_key].valuedef __setitem__(self, key, value):# 计算是否需要扩容if (self._used / self._array_len) > SimpleDict.Load_factor:self._new_array()#根据键的hash值来计算得出位置索引hash_key = self._hash(key)new_key = self._second_hash(hash_key)while True:if self._array[hash_key] is None or key == self._array[hash_key].key:break# 发生哈希碰撞根据二次探查函数得出下一个索引的位置hash_key = next(new_key)if abs(hash_key) >= self._array_len:self._new_array()hash_key = self._hash(key)# 找到空位将键值对象放入self._array[hash_key] = self.dictObj(key, value)self._used += 1def __delitem__(self, key):hash_key = self._hash(key)if key != self._array[hash_key].key:for new_key in self._second_hash(hash_key):if key == self._array[new_key].key:hash_key = new_keyself._array[hash_key] = Noneself._used -= 1def _hash(self, key):# 计算哈希值return hash(key) & (self._array_len-1)def _second_hash(self, hash_key):# 简单的二次探查函数实现count = 1for i in range(self._array_len):new_key = hash_key + count**2if abs(new_key) < self._array_len:yield new_keynew_key = hash_key - count**2if abs(new_key) < self._array_len:yield new_keycount += 1def _new_array(self):# 扩容old_array = self._arrayself._array_len = self._array_len * 2 # 扩容2倍大小self._array = SimpleArray(self._array_len)for i in range(len(old_array)):dictObj = old_array[i]if dictObj is not None:self[dictObj.key] = dictObj.valuedef __str__(self):result = ", ".join("%s:%s"%(obj.key, obj.value)for obj in self._arrayif obj is not None)return "{" + result + "}"if __name__ == '__main__':d = SimpleDict()for i in range(20):d[str(i)] = iprint(d)print(d["10"])del d["11"]print(d)


链接法

优点

  1. 对于记录总数频繁可变的情况,处理的比较好(也就是避免了动态调整的开销)
  2. 由于记录存储在结点中,而结点是动态分配,不会造成内存的浪费,所以尤其适合那种记录本身尺寸(size)很大的情况,因为此时指针的开销可以忽略不计了
  3. 删除记录时,比较方便,直接通过指针操作即可

缺点

  1. 存储的记录是随机分布在内存中的,这样在查询记录时,相比结构紧凑的数据类型(比如数组),哈希表的跳转访问会带来额外的时间开销
  2. 如果所有的 key-value 对是可以提前预知,并之后不会发生变化时(即不允许插入和删除),可以人为创建一个不会产生冲突的完美哈希函数(perfect hash function),此时封闭散列的性能将远高于开放散列
  3. 由于使用指针,记录不容易进行序列化(serialize)操作

其中有很重要的两个参数影响其性能: 初始容量和加载因子

dict:默认初始容量为8,加载因子为2/3

HashMap: 默认初始容量为16, 加载因子为0.75

两者相同的是扩容的长度必需是2的N次方

加载dict_Python的dict实现原理和Java的HashMap之间的区别相关推荐

  1. 使用DriverManager动态加载JDBC驱动时,报:java.sql.SQLException: No suitable driver found for xxxx 错误

    参考文章: yanbin.blog - 自定义类加载器动态加载 JDBC 驱动 项目场景: 使用DriverManager动态加载JDBC驱动时,报:java.sql.SQLException: No ...

  2. 加载主类 Hello 时出现 LinkageError java.lang.UnsupportedClassVersionError

    JDK17和eclipse 2021-09版本 运行时报错: 加载主类 Hello 时出现 LinkageError java.lang.UnsupportedClassVersionError: H ...

  3. 描述一下JAVA的加载过程_JVM源码分析之Java类的加载过程

    简书 占小狼 转载请注明原创出处,谢谢! 趁着年轻,多学习 背景 最近对Java细节的底层实现比较感兴趣,比如Java类文件是如何加载到虚拟机的,类对象和方法是以什么数据结构存在于虚拟机中?虚方法.实 ...

  4. 原来热加载如此简单,手动写一个 Java 热加载吧

    1. 什么是热加载 热加载是指可以在不重启服务的情况下让更改的代码生效,热加载可以显著的提升开发以及调试的效率,它是基于 Java 的类加载器实现的,但是由于热加载的不安全性,一般不会用于正式的生产环 ...

  5. 错误: 找不到或无法加载主类 helloworld_你还不知道Java的类加载机制?

    上篇分析完一个class文件后,我们再来回答几个问题 一.面试题                    1.什么是类的加载                                        ...

  6. 多项目加载顺序修改_面试官:Java 类在 Tomcat 中是如何加载的?

    说到本篇的Tomcat类加载机制,不得不说翻译学习Tomcat的初衷. 之前实习的时候学习JavaMelody的源码,但是它是一个Maven的项目,与我们自己的Web项目整合后无法直接断点调试. 后来 ...

  7. 单点登录原理和java实现简单的单点登录

    摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软件系统当中.本文从业务的角度分析了单点登录的需求和应用领域:从技术本身的角度分析了单点登录技术的内部机制和实现手段,并且给出Web-SSO ...

  8. RSA加密算法原理和java简单实现

    数学 RSA加密算法中,用到素数.互质数.指数运算.模运算等几个数学知识. 素数 素数又称质数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数. 互质数 百度百科:公因数只有 ...

  9. 代理重加密(Proxy Re-Encryption)技术原理和Java代码实现

    欢迎关注公众号:区块链之美, 致力于区块链技术研究,传播区块链技术和解决方案.区块链应用落地.区块链行业动态等. 1. 代理重加秘的应用介绍 由于大部分的云服务供应商并不能完全值得信任,云服务供应商可 ...

最新文章

  1. 移动磁盘格式化了的资料寻回方法
  2. ios -使用NSLayoutConstraint实现多个view等宽等高等间距
  3. QQ互联OAuth2.0 .NET SDK 发布以及网站QQ登陆示例代码(转)
  4. 【MapReduce】
  5. SAP UI5 应用开发教程之六十四 - 基于 OData V4 的 SAP UI5 表格控件如何实现 filter(过滤) 和 sort(排序)功能
  6. jquery的ajax,请求JSON数据。
  7. 基于属性加密的ABE算法的应用场景思考展望
  8. math.pow int_Java Math类static int min(int i1,int i2)与示例
  9. python3 xpath_Python3使用xpath解析
  10. Jquery Ztree异步加载树
  11. Netty工作笔记0074---handler链调用机制实例1
  12. PCL中把txt文件转换成.pcd文件(很简单)
  13. day-1 用python编写一个简易的FTP服务器
  14. 嵌入式软件c语言笔试题
  15. Python 网络爬虫——爬取小说网站
  16. 求助,DatabaseError: (cx_Oracle.DatabaseError) ORA-00904: xiaoli: 标识符无效
  17. android 扫描wifi列表重复,Android Settings 出现重复的WIFI SSID,多个相同的WIFI SSID
  18. mysql时间戳转换大日期 2038 以上 2099
  19. 概率论考点之指数分布,泊松分布及积分(一维随机变量内容)
  20. MongoDB启动shutting down with code:100处理

热门文章

  1. TCP/IP / 如何进行堵塞控制?
  2. 实时对讲是怎么发起的_QQ可实时显示手机电量并展示给好友 近半投票者支持该功能...
  3. java入门第六天课程_Java基础知识——第六天
  4. https网站引用http路径的js和css失效解决办法
  5. python基础教程(第二版)
  6. MongoDB 基础教程CURD帮助类
  7. 真核转录组(denovo/resequencing)及案例分析
  8. 攻打医院服务器的SamSam勒索木马分析
  9. iOS开发-63】Unknown type name CGRect,did you mean Rect?的解决方案
  10. SVN 版本服务器搭配全过程详解(服务端、客户端)[转]