2013-01-07 187 views
1

我正在寫一個簡單的哈希表與一組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']] 

回答

5

HT = [ [] ] * size使得size數指針到同一列表add_HT這裏不是問題。您需要將HT定義爲[[] for i in xrange(size)]

4

您將HT定義爲十個引用單個列表。取而代之的是,它是這樣的:

HT = [[] for _ in xrange(size)] 
0

這裏是正確的版本:

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'], [], [], [], [], [], [], [], []] 
>>> 
3

波動性和kindall已經說明,HT = [ [] ] * size作出了同樣的10個人副本空的list,而不是10個不同的空list s。 list身份總是咬新手程序員 - 偶爾甚至會咬專家。

他們已經向您展示瞭如何解決問題並獲得10個不同的空list s。但還有另一種解決這個問題的方法。如果你可以重寫你的程序發生變異的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)] 

有時候使事物不可變使代碼更簡單,有時更復雜。 (在這種情況下,我認爲第一個不可變版本就像可變版本一樣簡單,但第二個不可讀。)有時它會使代碼更快,有時會更慢。 (在這種情況下,快速測試顯示第一個速度大致相同,但第二個速度慢了50倍,並且使用了更多的內存;另一方面,使用PyPy而不是CPython,它們分別爲15%和30%比較慢,分別是......)但是它總是讓人更容易推理 - 你不必擔心對象身份。除了讓事情更容易編寫,更易於閱讀和更快速以外,還有一個必須考慮的折衷。但值得知道如何去做。