TL; DR: Hash tabloları O(1)
, hash fonksiyonunuzu evrensel bir hash fonksiyonları ailesinden rastgele bir şekilde seçerseniz beklenen en kötü durum süresini garanti eder . Beklenen en kötü durum, ortalama durumla aynı değildir.
Yasal Uyarı: Karma tabloların olduğunu resmen kanıtlamıyorum O(1)
, çünkü bu videoya Coursera'dan [ 1 ] bir göz atın . Ayrıca hash tablolarının amortize edilmiş yönlerini de tartışmıyorum . Bu, hash ve çarpışmalar hakkındaki tartışmaya ortogonaldir.
Diğer cevaplarda ve yorumlarda bu konuyla ilgili şaşırtıcı derecede büyük bir kafa karışıklığı görüyorum ve bu uzun cevapta bazılarını düzeltmeye çalışacağım.
En kötü durum hakkında akıl yürütme
Farklı en kötü durum analizi türleri vardır. Şimdiye kadar burada çoğu yanıtın yaptığı analiz en kötü durum değil , daha ziyade ortalama bir durumdur. [ 2 ]. Ortalama vaka analizi daha pratik olma eğilimindedir. Belki algoritmanızın bir en kötü durum girdisi vardır, ancak aslında diğer tüm olası girdiler için iyi çalışır. Sonuç olarak, çalışma zamanınız üzerinde çalıştığınız veri kümesine bağlıdır .
get
Bir karma tablo yönteminin aşağıdaki sözde kodunu düşünün . Burada, çarpışmayı zincirleme yoluyla ele aldığımızı varsayıyorum, bu nedenle tablonun her girişi bağlantılı bir listedir.(key,value)
çift . Ayrıca, grup sayısının m
sabit olduğunu O(n)
, ancak n
girişteki öğelerin sayısı nerede olduğunu varsayıyoruz .
function get(a: Table with m buckets, k: Key being looked up)
bucket <- compute hash(k) modulo m
for each (key,value) in a[bucket]
return value if k == key
return not_found
Diğer yanıtların da işaret ettiği gibi, bu ortalama O(1)
ve en kötü durumda çalışır O(n)
. Burada meydan okuyarak bir ispatın küçük bir taslağını yapabiliriz. Zorluk şu şekildedir:
(1) Karma tablo algoritmanızı bir düşmana verirsiniz.
(2) Düşman onu inceleyebilir ve istediği kadar hazırlık yapabilir.
(3) Nihayet düşman size bir boyut girdisi verir n
, tablonuza eklemeniz için size bir .
Soru şu: hash tablonuz rakip girdilere göre ne kadar hızlı?
Adım (1) 'den düşman, hash fonksiyonunuzu bilir; adım (2) sırasında düşman, örneğin bir grup öğenin karmasını rasgele hesaplayarak, n
aynı öğelerin bir listesini oluşturabilir hash modulo m
; ve sonra (3) 'te size bu listeyi verebilirler. Ama bakalım, tüm n
öğeler aynı gruba hash oluşturduğundan, algoritmanızın bu O(n)
paketteki bağlantılı listeyi geçmesi zaman alacaktır . Meydan okumayı kaç kez denersek deneyelim, rakip her zaman kazanır ve algoritmanız bu kadar kötüdür, en kötü durumO(n)
.
Hashing nasıl O (1) olur?
Önceki zorlukta bizi şaşırtan şey, düşmanın hash işlevimizi çok iyi bilmesi ve bu bilgiyi mümkün olan en kötü girdiyi oluşturmak için kullanabilmesiydi. Ya her zaman tek bir sabit karma işlevi kullanmak yerine, aslında H
algoritmanın çalışma zamanında rastgele seçebileceği bir dizi karma işlevimiz olsaydı ? Merak ediyorsanız H
, buna evrensel bir hash fonksiyonları ailesi denir [ 3 ]. Pekala, buna biraz rastgelelik eklemeyi deneyelim .
Öncelikle, hash tablomuzun da bir tohum içerdiğini r
ve r
inşa sırasında rastgele bir sayıya atandığını varsayalım . Bir kez atarız ve ardından bu karma tablo örneği için sabitlenir. Şimdi sözde kodumuzu tekrar gözden geçirelim.
function get(a: Table with m buckets and seed r, k: Key being looked up)
rHash <- H[r]
bucket <- compute rHash(k) modulo m
for each (key,value) in a[bucket]
return value if k == key
return not_found
Meydan okumayı bir kez daha denersek: 1. adımdan itibaren rakip, sahip olduğumuz tüm hash fonksiyonlarını bilebilir H
, ancak şimdi kullandığımız özel hash fonksiyonu buna bağlıdır r
. Değeri r
kendi yapımıza özeldir, rakip onu çalışma zamanında inceleyemez veya önceden tahmin edemez, bu yüzden bizim için her zaman kötü olan bir liste yapamaz. En adımda (2) hasım bir işlevi seçer olduğunu varsayalım hash
içinde H
rastgele, o da bir listesini el sanatları n
altında çarpışmaları hash modulo m
ve gönderdiği zamanında o parmak kapısı adım (3), için H[r]
aynı olacaktır hash
onlar seçti.
Bu, rakip için ciddi bir bahis, hazırladığı liste altında çarpışıyor hash
, ancak diğer hash işlevlerinin altında rastgele bir girdi olacak H
. Bu bahsi kazanırsa, çalışma süremiz eskisi O(n)
gibi en kötü durum olacak , ancak kaybederse, bize sadece ortalama O(1)
süreyi alan rastgele bir girdi veriliyor . Ve gerçekten de çoğu zaman düşman kaybedecek, her |H|
meydan okumayı yalnızca bir kez kazanır ve biz yapabiliriz.|H|
çok büyük olabiliriz.
Bu sonucu, rakibin her zaman meydan okumayı kazandığı önceki algoritmayla karşılaştırın. Burada biraz el sallamak, ancak çoğu zaman düşman başarısız olacağından ve bu, düşmanın deneyebileceği tüm olası stratejiler için doğrudur, bunun sonucu olarak en kötü durum olsa da O(n)
, beklenen en kötü durum gerçektir O(1)
.
Yine, bu resmi bir kanıt değil. Bu beklenen en kötü durum analizinden aldığımız garanti, çalışma süremizin artık herhangi bir belirli girdiden bağımsız olmasıdır . Motive olmuş bir düşmanın kolayca kötü girdiler üretebileceğini gösterdiğimiz ortalama vaka analizinin aksine, bu gerçekten rastgele bir garantidir.