09-01字典的实现方式
字典的实现方式
拉链法
i = hash(key) % solt
假设槽位有32个, 那么得到的值很有可能会有冲突, i为最后的该值处于哪个槽位。
将每个槽位做一个列表, 存值的时候append, 取值的时候遍历。
如果算法足够好的话, 就几乎能实现近似O(1)了
实现:
In [58]: solts = []
...: solts_num = 32
...:
...: for _ in range(solts_num):
...: solts.append([])
...: def put(solts, key, value):
...: i = hash(key) % solts_num
...: solts[i].append((key, value))
...: def get(solts, key):
...: i = hash(key) % solts_num
...: for k, v in solts[i]:
...: if k == key:
...: return v
...: raise KeyError(k)
...:
In [59]: put(solts, 'r', 2)
In [60]: solts
Out[60]:
[[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[('r', 2)],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]]
In [66]: put(solts, 'd', 2)
In [67]: get(solts, 'd')
Out[67]: 2
版本2:实现插入重复key的处理方式
In [69]: solts = []
...: solts_num = 32
...:
...: for _ in range(solts_num):
...: solts.append([])
...: def put(solts, key, value):
...: i = hash(key) % solts_num
...: p = -1
...: for p, (k, v) in enumerate(solts[i]):
...: if k == key:
...: break
...: else:
...: solts[i].append((key, value))
...: return
...: if p >=0:
...: solt[i][p] = (key, value)
...: def get(solts, key):
...: i = hash(key) % solts_num
...: for k, v in solts[i]:
...: if k == key:
...: return v
...: raise KeyError(k)
...:
版本3:类的实现
In [74]: class Dict:
...: def __init__(self, num):
...: self.__solts__ = []
...: self.num = num
...: for _ in range(num):
...: self.__solts__.append([])
...: def put(self, key, value):
...: i = hash(key) % self.num
...: for p, (k, v) in enumerate(self.__solts__[i]):
...: if k == key:
...: break
...: else:
...: self.__solts__[i].append((key, value))
...: return
...: self.__solts__[i][p] = (key, value)
...: def get(self, key):
...: i = hash(key) % self.num
...: for k, v in self.__solts__[i]:
...: if k == key:
...: return v
...: raise KeyError(key)
...:
In [75]: d = Dict(32)
In [76]: d.put('r', 2)
In [77]: d.put('d', 2)
In [78]: d.get('r')
Out[78]: 2
版本4:类的实现, 添加keys方法实现
In [79]: class Dict:
...: def __init__(self, num):
...: self.__solts__ = []
...: self.num = num
...: for _ in range(num):
...: self.__solts__.append([])
...: def put(self, key, value):
...: i = hash(key) % self.num
...: for p, (k, v) in enumerate(self.__solts__[i]):
...: if k == key:
...: break
...: else:
...: self.__solts__[i].append((key, value))
...: return
...: self.__solts__[i][p] = (key, value)
...: def get(self, key):
...: i = hash(key) % self.num
...: for k, v in self.__solts__[i]:
...: if k == key:
...: return v
...: raise KeyError(k)
...: def keys(self):
...: ret = []
...: for solt in self.__solts__:
...: for k, _ in solt:
...: ret.append(k)
...: return ret
...:
In [80]: d = Dict(32)
In [81]: d.put('r', 2)
In [82]: d.put('d', 2)
In [83]: d.keys()
Out[83]: ['d', 'r']
开地址法
i = hash(key) % solt 可以用相同的算法来做
假设槽位有32个, 那么得到的值很有可能会有冲突, i为最后的该值处于哪个槽位。
不同的是, 值冲突后的处理方法不同。
i = fn(key, i) # 如果被占用, 就用算法去找下一个槽。如果槽还是被占用, 就会去找下一个槽。
取值的时候, 用函数一个一个找下去。
集合在底层的实现, 就是一个忽略了value的字典