引言:这个题目其实源于很久之前的一次 Uber 面试,码工换工作无非就是刷 leetcode ,研究如何翻转二叉树之类的算法问题,所以头一次在电话里听到这道题的时候还是挺耳目一新的。当时顺利写出来了,也通过了电面,但觉得还是有不完善的地方,比如说代码不够 “Pythonic” 等,所以趁着周天晚上闲着无事,又拿出来写了写
HashTable 本身没啥好说的,中文叫”哈希表“或者”散列表“,这个数据结构用来存储”键-值“结构的数据,可以做到常数级时间复杂度的查找。
HashTable有两个问题需要解决,首先是key值哈希化,我们可以借助Python自带的hash函数解决key的哈希编码问题。其次是Hash 冲突的解决机制,在这里只考虑最简单的一种,即将同一个 hash 值下的不同的 key 存放在数组的同一个位置,以链表形式保存
class MyDict(object):
def __init__(self, size=10000):
# 用list初始化hashtable,并且每个位置都对应一个子list已解决hash冲突问题
self.hash_list = [list() for _ in range(size)]
self.size = size
def __setitem__(self, key, value):
# 利用python自带的hash函数,对key哈希并对size取模
# hased_key位置没有值就追加,否则覆盖
hashed_key = hash(key) % self.size
for item in self.hash_list[hashed_key]:
if item[0] == key:
item[1] = value
break
else:
self.hash_list[hashed_key].append([key, value])
def __getitem__(self, key):
# return: key所对应的value
# 没有key,就抛出keyError
for item in self.hash_list[hash(key) % self.size]:
if item[0] == key:
return item[1]
raise KeyError(key)
def __repr__(self):
# hashtable打印
result = []
for sub_list in self.hash_list:
if not sub_list:
continue
for item in sub_list:
result.append(str(item[0]) + ": " + str(item[1]))
return "{" + ", ".join(result) + "}"
def __contains__(self, key):
# 是否包含key,实现in操作符的功能
for item in self.hash_list[hash(key) % self.size]:
if item[0] == key:
return True
return False
# 通过调用 keys() 、values() 、items() 来分别遍历键、值、键值对
def __iterate_kv(self):
for sub_list in self.hash_list:
if not sub_list:
continue
for item in sub_list:
yield item
def __iter__(self):
for kv_pair in self.__iterate_kv():
yield kv_pair[0]
def keys(self):
return self.__iter__()
def values(self):
for kv_pair in self.__iterate_kv():
yield kv_pair[1]
def items(self):
return self.__iterate_kv()
md = MyDict()
md
{}
md['a'] = 1
md['b'] = 2
md['a']
>>> 1
md['a'] = 3
md['a']
>>> 3
md['c']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-15-274bae202805> in <module>()
----> 1 md['c']
<ipython-input-9-35e8cb6491bb> in __getitem__(self, key)
24 if item[0] == key:
25 return item[1]
---> 26 raise KeyError(key)
27
28 def __repr__(self):
KeyError: 'c'
md
>>> {a: 3, b: 2}
list(md.keys())
>>> ['a', 'b']
>
list(md.values())
>>> [3, 2]
>
list(md.items())
>>> [['a', 3], ['b', 2]]
'a' in md
>>> True
md.__contains__('c')
>>> False
参考: