我写了一组10名列表一个简单的哈希表。 该指数是使用内置在计算hash()
然后模台尺寸。 然而,当我尝试的对象遗愿清单追加该索引处,它被附加到每一桶列表,而不是。 我试着定义add_HT不同的方式,但我一直得到相同的结果。 我究竟做错了什么?
size = 10
HT = [ [] ] * size
def add_HT(data):
index = hash(data) % size
HT[index].append(data)
print HT
[[], [], [], [], [], [], [], [], [], []]
add_HT('hello')
[['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello']]
HT = [ [] ] * size
使得size
指针指向同一列表的数目。 add_HT
是不是这里的问题。 您需要定义HT
为[[] for i in xrange(size)]
。
你定义HT
十只引用一个列表。 取而代之的是,它是这样的:
HT = [[] for _ in xrange(size)]
如波动和kindall已经解释的, HT = [ [] ] * size
使得同一空的10个拷贝list
,而不是10个不同的空list
秒。 list
身份始终咬新手程序员,偶尔咬即使是行家。
他们已经展示了如何解决这个问题,并得到10角不同的空list
秒。 但有解决这个问题的另一种方式。 如果你可以重写你的程序发生变异的list
s的一切,这不要紧,他们是否是相同的或不:
def add_HT(data):
index = hash(data) % size
HT[index] = HT[index] + [data]
现在:
>>> add_HT('hello')
>>> add_HT('goodbye')
>>> HT
[['goodbye'], ['hello'], [], [], [], [], [], [], [], []]
这里发生的事情是,你正在做每次追加一次新的水桶,并更换旧的桶,所以水桶是不可变的。 (您可能要并将其作为tuple
s,而不是list
S,以确保你不小心发生变异他们。)
你甚至可以更远借此,并不仅仅是每个HT[i]
一成不变的,而且HT
本身:
def add_HT(data):
global HT
index = hash(data) % size
HT = [bucket if i != index else bucket + [data] for i, bucket in enumerate(HT)]
有时使事情一成不变使代码更简单,有时会更复杂。 (在这种情况下,我认为第一个不可改变的版本只是尽可能的可变版本简单,但第二个是可读的要少得多。)有时它使代码更快,有时慢。 (在这种情况下,快速测试示出了第一大约相同的速度,但第二50X慢,并且使用了大量的更多的存储器。在另一方面,使用代替CPython的PyPy,他们不是15%和30%较慢,分别为...),但它总是更容易推理,你不必担心对象的身份。 除了当它使事情更容易编写,更易于阅读,快,还有,你必须考虑的权衡。 但它是值得知道如何做到这一点。
下面是正确的版本:
size = 10
HT = [ [] for x in range(size)]
def add_HT(data):
index = hash(data) % size
HT[index].append(data)
print HT
add_HT('hello')
print HT
输出:
>>>
[[], [], [], [], [], [], [], [], [], []]
[[], ['hello'], [], [], [], [], [], [], [], []]
>>>