Neden (çarpışmasız) karma bir arama gerçekten O (1)?


10

Feragatname: Burada ve Stackoverflow'da benzer sesli sorular olduğunu biliyorum. Ama hepsi çarpışmalarla ilgili, istediğim bu değil.

Sorum şu: neden Çarpışması edilir az arama O(1)ilk etapta?

Diyelim ki bu hashtable var:

Hash  Content
-------------
ghdjg Data1
hgdzs Data2
eruit Data3
xcnvb Data4
mkwer Data5
rtzww Data6

Şimdi khash fonksiyonunun h(k)verdiği anahtarı arıyorum h(k) = mkwer. Ancak arama, karmanın mkwer5. konumda olduğunu nasıl bilebilir ? O(n)Bulmak için neden tüm tuşlar arasında gezinmek zorunda değil? Karmalar bir çeşit gerçek donanım adresi olamaz çünkü verileri hareket ettirme yeteneğini kaybederdim. Ve bildiğim kadarıyla, hashtable hash'lerde sıralanmamıştır (öyle olsa bile, arama da sürer O(log n))?

Bir hash bilmek, tablodaki doğru yeri bulmaya nasıl yardımcı olur?

Yanıtlar:


25

Hash işlevi , gibi bir dize döndürmez mkwer. Doğrudan dizideki öğenin konumunu döndürür. Örneğin, karma tablonuzda on giriş varsa, karma işlevi 0-9 aralığında bir tamsayı döndürür.


1
Teşekkürler. :) Benim hatam MD5 veya SHA gibi hashtable bir hash fonksiyonu düşünüyordum. Ama bir karma elbette düşünmediğim bir tamsayı olabilir. Şimdi ne arayacağımı bildiğime göre, hızlı bir şekilde iyi bir örnek bile buldum: PHP'nin karma işlevi: github.com/php/php-src/blob/PHP-5.6.10/Zend/zend_hash.h#L237
Foo Bar

13
@FooBar: MD5 ve SHA da girişten tek sayı hesaplar, karma formları onaltılı biçimde konuşmak çok yaygındır. Bellek adresleri nadiren ondalık sayı olarak değerlendirilir.
nperson325681

4
Ayrıca, MD5 vb. Doğrudan dizi dizini olarak kullanılmak için çok uzun. Alt n bitleri gibi, karmanın bir kısmını kullanmak mümkün olacaktır .
chirlu

6

Hash işlevi, verilen dizeden dizi konumunu hesaplar . Bu mükemmel bir karma ise, hiçbir çarpışma olmadığı anlamına gelir, büyük olasılıkla dizi, eleman sayısından en az iki kat daha büyüktür.

Mesela, harfleri için çok zayıf bir karma vereceğim, sadece mekanizmayı ilust etmek için:
0) 1) dizedeki her karakter için ascii değerini al, küçük harfse 'a', büyük harfle 'A' çıkar, x'e değer ekle. x = x m o d 52 2) elde edilen sayı örneğin 15, dizi indeksidir. x=0;
x=xmod52

Bu çok basit karma (sınırlı ve çarpışmalara yatkın), karma mekanizmasındaki diğer karmalardan farklıdır, verilen girdiyi dikkate almaz. Daha gelişmiş şemada, karma öğe sayısına göre ayarlanmış daha büyük sayıdır. Çarpışma olmaması için tüm girdiler için mükemmel karma üretilir.

Bu çünkü dizeden hash hesaplamak fonksiyonun ne kadar karmaşık hesaplandığına bağlıdır, ancak eleman sayısına bağlı değildir.O(1)

Mükemmel karma durumunda, elemanlar eklendiğinde yeniden hesaplanır, dizi yükü büyük olduğunda çarpışmaların olduğu daha basit durum, dizi boyutu artar, fonksiyon daha büyük çıktı modüü alır ve elemanlar yeni yerlere kaydırılır.h(k)

nthn(sizeofelement)


1
Arama , tablonun karmanın nerede olduğunu nasıl biliyor ? Ne sipariş edilmiş ne de donanım adresleri.
Foo Bar

h("xcnvb")=8

Ancak her dizin doldurulmaz. Verilerle dolu 1, 4, 8, 90 ve 223 hashım varsa, arama doğru yeri nasıl bulur? Bu durumda "90" 4 numaralı konumdadır, çünkü diğer birçok dizin mevcut değildir. Ve boş bir hashtable, tüm olası pozisyonlara sahip sonsuz büyüklükte değildir !?
Foo Bar

HaHa(h("xcnvb"))=Ha[90]

Karma işlevi diziye bir dizin döndürmez. Bunun yerine, diziye eşleştirilebilecek öngörülebilir bir sayı döndürür. Bu genellikle diğer işlenen gibi karma tablo kovalarının sayısı ile modül operatörü kullanılarak yapılır .
Christopher Schultz

3

David Richerby'nin cevabını genişletmek için, " hash fonksiyonu " terimi biraz aşırı yüklü. Genellikle, bir karma işlevi hakkında konuştuğumuzda, MD5, SHA-1 veya .hashCode()bazı girişleri tek bir sayıya dönüştüren Java'nın yöntemi gibi bir şey düşünürüz . Ancak bu sayının alanı içeri verileri saklamaya çalıştığınız Hashtable aynı boyutta olması çok olası değildir (yani maksimum değerdir) (MD5 SHA-1 20 bayt, 16 bayt ve. .hashCode()Bir olduğunu int- 4 bayt).

Yani sorunuz bir sonraki adımla ilgili - rastgele girişleri rakamlarla eşleştirebilen bir karma fonksiyonumuz olduğunda, bunları belirli bir boyuttaki veri yapısına nasıl koyabiliriz? Başka bir fonksiyon ile "hash fonksiyonu" da denir!

Böyle bir işlevin önemsiz bir örneği modülodur ; modulo içeren bir dizideki belirli bir dizine belirli sayıda rasgele boyut eşleştirebilirsiniz. Bu CLRS'de "bölme yöntemi" olarak tanıtılmıştır:

kmkm

h(k)=km

...

mmm=2ph(k)pk

~ Algoritmalara Giriş, §11.3.1 - CLRS

m

Java , iki boyutlu dizilerin gücünü kullanabilmesi HashMapiçin zayıf .hashCode()uygulamaları hesaba katmak için ön işlem adımı uygulayan bölme yönteminin değiştirilmiş bir sürümünü kullanır . .getEntry()Yöntemde neler olduğunu tam olarak görebilirsiniz (yorumlar benimdir):

 // hash() transforms key.hashCode() to protect against bad hash functions
 int hash = (key == null) ? 0 : hash(key.hashCode());
 // indexOf() converts the resulting hash to a value between 0 and table.length-1
 for (Entry<K,V> e = table[indexFor(hash, table.length)];
     ...

Java 8 HashMap, daha hızlı, ancak okunması biraz daha zor olan bir yeniden yazma getirdi . Bununla birlikte, dizin arama için aynı genel ilkeyi kullanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.