Python之美[从菜鸟到高手]--读"一道面试题看 HashMap 的存储方式"的联想
来源:互联网 发布:什么是淘宝长尾关键词 编辑:程序博客网 时间:2024/05/14 05:41
今天在伯乐在线 上看到一篇文章,一道面试题看 HashMap 的存储方式,也就是问:
在 HashMap 中存放的一系列键值对,其中键为某个我们自定义的类型。放入 HashMap 后,我们在外部把某一个 key 的属性进行更改,然后我们再用这个 key 从 HashMap 里取出元素,这时候 HashMap 会返回什么?
如何面试者直接答“这要看自定义类型的hash值了”,我想面试官会非常满意。
联想到python中dict的实现,python中字典一般不存在这个问题,因为key的hash值默认是id值,一个对象的id是固定的。
看如下代码:
我们可以通过__hash__修改默认hash值,所以__hash__方法还是要看具体业务逻辑,比如我们业务任务name值一样就是同一个对象,看如下代码:
class B:def __init__(self,name):self.name=namedef __hash__(self):return hash(self.name)d={}b1=B('skycrab')b2=B('skycrab1')d[b1]=1d[b2]=2b2.name='skycrab'd[b2]=3print d我信心满满的认为name为‘skycrab‘的值会被更新为3,可事实如下:
{<__main__.B instance at 0x02543210>: 2, <__main__.B instance at 0x02543210>: 3, <__main__.B instance at 0x025436C0>: 1}
这让我百思不得其解,hash值明明一样,为什么会认为是不同对象,导致增加了一个。突然灵光一闪,难道key也需要做比较?打开python源码我们看看lookdict函数,
当更新字典时会去寻找合适的hashtable位置,调用的就是lookdict函数。
static dictentry *lookdict(dictobject *mp, PyObject *key, register long hash){register size_t i;register size_t perturb;register dictentry *freeslot;register size_t mask = (size_t)mp->ma_mask;dictentry *ep0 = mp->ma_table;register dictentry *ep;register int cmp;PyObject *startkey;i = (size_t)hash & mask;ep = &ep0[i];if (ep->me_key == NULL || ep->me_key == key)return ep;if (ep->me_key == dummy)freeslot = ep;else {if (ep->me_hash == hash) {startkey = ep->me_key;cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); //比较key的值if (cmp < 0)return NULL;if (ep0 == mp->ma_table && ep->me_key == startkey) {if (cmp > 0) //只有key相等才会返回已有的位置,否则会寻找一个新的位置return ep;}else {/* The compare did major nasty stuff to the * dict: start over. * XXX A clever adversary could prevent this * XXX from terminating. */ return lookdict(mp, key, hash); }}freeslot = NULL;}
上面是lookdict的部分源码(最后没有大括号),如上代码注释,原来只有hash值一样且key值相等才有更新。那么这就好办了,定义__eq__方法即可:
class B:def __init__(self,name):self.name=namedef __hash__(self):return hash(self.name)def __eq__(self,r):if self.name == r.name:return Trueelse:return Falsed={}b1=B('skycrab')b2=B('skycrab1')d[b1]=1d[b2]=2b2.name='skycrab'd[b2]=3print d这下结果终于符合期望了,{<__main__.B instance at 0x025F2620>: 2, <__main__.B instance at 0x025F25F8>: 3}
这里我们扩展一下,python中的dict默认采用hash_map的存储结构,所以查找效率很高,但hash_map的查找效率不稳定。
hash_map的时间复杂度在O(1)-O(N),而基于树结构的map时间复杂度O(logN),比较稳定。
所以在C++中使用hash_map还是map是有考究的,具体可以看看【C++对话系列-产生真正的hash对象】一节。
- Python之美[从菜鸟到高手]--读"一道面试题看 HashMap 的存储方式"的联想
- 一道面试题看 HashMap 的存储方式
- 一道面试题看 HashMap 的存储方式
- 一道面试题看 HashMap 的存储方式
- 一道面试题看 HashMap 的存储方式
- 一道面试题看 HashMap 的存储方式
- (转)一道面试题看 HashMap 的存储方式
- 一道面试题看 HashMap 的存储方式
- 一道面试题看 HashMap 的存储方式
- 一道SQL的面试题之联想
- 一道SQL的面试题之联想
- Python之美[从菜鸟到高手]--urllib源码分析
- Python之美[从菜鸟到高手]--urlparse源码分析
- Python之美[从菜鸟到高手]--NotImplemented小析
- Python之美[从菜鸟到高手]--NotImplemented小析
- Python之美[从菜鸟到高手]--NotImplemented小析
- Python之美[从菜鸟到高手]--NotImplemented小析
- Java之美[从菜鸟到高手演变]之HashMap、HashTable
- mysql默认字符集的修改方法
- Linux的挂载
- 拥抱 Rails 4 —— 详述 Rails 4 的新变化
- ORACLE 日期加减操作
- 安装系统
- Python之美[从菜鸟到高手]--读"一道面试题看 HashMap 的存储方式"的联想
- connect by
- 视频格式D1
- ASP.NET-关于Container dataitem 与 eval方法介绍
- 安装虚拟机报错解决办法 TheVMware Authorization Service is not running
- 关于热血传奇actor绘制的分析与思考
- linux yum命令详解
- 五彩趣味运动会的起源与发展
- Struts2+Hibernate+Spring整合