İkili arama ağaçlarının karma tablolara göre avantajları nelerdir?
Karma tablolar, Theta (1) zamanındaki herhangi bir öğeyi arayabilir ve bir öğe eklemek kadar kolaydır ... ancak bunun tersi olan avantajlardan emin değilim.
İkili arama ağaçlarının karma tablolara göre avantajları nelerdir?
Karma tablolar, Theta (1) zamanındaki herhangi bir öğeyi arayabilir ve bir öğe eklemek kadar kolaydır ... ancak bunun tersi olan avantajlardan emin değilim.
Yanıtlar:
İkili Arama Ağaçlarının (referans tabanlı) bellek açısından verimli olduğunu unutmayın. İhtiyaç duyduklarından daha fazla bellek ayırmazlar.
Örneğin, bir karma işlevinin bir aralığı R(h) = 0...100
varsa, sadece 20 öğeye hashing yapıyor olsanız bile, 100 (işaretçilerden) öğelerden oluşan bir dizi ayırmanız gerekir. Aynı bilgileri depolamak için bir ikili arama ağacı kullanacak olsaydınız, yalnızca ihtiyaç duyduğunuz kadar alanı ve bağlantılar hakkında bazı meta verileri ayırırdınız.
Hiç kimsenin belirtmediği bir avantaj, ikili arama ağacının verimli bir şekilde aralık aramaları yapmanıza izin vermesidir.
Fikrimi açıklamak için, aşırı bir örnek vermek istiyorum. Anahtarları 0 ile 5000 arasında olan tüm öğeleri almak istediğinizi varsayalım. Ve aslında bu türden yalnızca bir öğe ve anahtarları aralıkta olmayan 10000 başka öğe vardır. BST, yanıt almanın imkansız olduğu bir alt ağaçta arama yapmadığı için, aralık aramalarını oldukça verimli bir şekilde yapabilir.
Bir karma tabloda aralık aramalarını nasıl yapabilirsiniz? Ya O (n) olan her kova alanını yinelemeniz gerekir, ya da 1,2,3,4… 'den 5000'e kadar her birinin var olup olmadığına bakmanız gerekir. (0 ile 5000 arasındaki tuşlar sonsuz bir kümedir? örneğin anahtarlar ondalık sayı olabilir)
İkili ağacın bir "avantajı", tüm öğeleri sırayla listelemek için üzerinden geçilebilmesidir. Bu bir Hash tablosu ile imkansız değildir, ancak hash uygulanmış bir yapıya tasarım olarak normal bir işlem değildir.
Diğer tüm iyi yorumlara ek olarak:
Karma tablolar genel olarak, ikili ağaçlara kıyasla daha az bellek okuması gerektiren daha iyi önbellek davranışına sahiptir. Bir karma tablo için, verilerinizi tutan bir referansa erişmeden önce normalde yalnızca tek bir okumaya maruz kalırsınız. İkili ağaç, dengeli bir varyant ise, k * lg (n) bellek okumaları için bazı sabit k'ler için bir şey gerektirir .
Öte yandan, bir düşman hash fonksiyonunuzu bilirse, hash masanızı çarpışmalar yapmaya zorlayarak performansını büyük ölçüde bozabilir. Çözüm, karma işlevini bir aileden rastgele seçmektir, ancak BST'nin bu dezavantajı yoktur. Ayrıca, karma tablo basıncı çok arttığında, genellikle pahalı bir işlem olabilecek karma tabloyu büyütme ve yeniden tahsis etme eğilimindesinizdir. BST'nin burada daha basit davranışı vardır ve aniden çok fazla veri tahsis etme ve yeniden düzenleme işlemi yapma eğiliminde değildir.
Ağaçlar, nihai ortalama veri yapısı olma eğilimindedir. Liste olarak hareket edebilir, paralel işlem için kolayca bölünebilir, O (lg n) sırasına göre hızlı çıkarma, ekleme ve arama yapabilir . Hiçbir şeyi özellikle iyi yapmazlar , ancak aşırı derecede kötü davranışları da yoktur.
Son olarak, BST'lerin (saf) işlevsel dillerde uygulanması, karma tablolara kıyasla çok daha kolaydır ve yıkıcı güncellemelerin uygulanmasını gerektirmez ( yukarıdaki Pascal'ın kalıcılık argümanı).
BSTs are much easier to implement in (pure) functional languages compared to hash-tables
- Gerçekten mi? Şimdi işlevsel bir dil öğrenmek istiyorum!
Bir ikili ağacın bir karma tabloya göre ana avantajları, ikili ağacın size bir karma tablo ile yapamayacağınız (kolay ve hızlı bir şekilde) iki ek işlem vermesidir.
Bazı rastgele anahtar değerlerine (veya en yakın yukarı / aşağı) en yakın (eşit olması gerekmez) öğeyi bulun
Ağacın içeriğini sıralı bir şekilde yineleyin
İkisi birbirine bağlıdır - ikili ağaç, içeriğini sıralı bir sırayla saklar, böylece sıralı sırayı gerektiren şeyler yapmak kolaydır.
Bir (dengeli) ikili arama ağacı, asimptotik karmaşıklığının aslında bir üst sınır olması avantajına da sahiptir, oysa karma tablolar için "sabit" zamanlar amortize edilmiş zamanlardır: Uygun olmayan bir hash fonksiyonunuz varsa, doğrusal zamana indirgenebilirsiniz. sabit değil.
Bir hashtable, ilk oluşturulduğunda daha fazla yer kaplar - henüz eklenecek olan öğeler için kullanılabilir yuvalara sahip olur (eklenmiş olsun ya da olmasın), bir ikili arama ağacı yalnızca ihtiyaç duyduğu kadar büyük olacaktır. olmak. Bir karma-tablo fazla oda ihtiyaç duyduğunda Ayrıca, başka yapıya genişleyen olabilir zaman alıcı olabilir, ama bu uygulamaya bağlı olabilir.
İkili bir arama ağacı, yeni bir ağacın döndürüldüğü ancak eski ağacın varlığını sürdürdüğü kalıcı bir arayüzle gerçekleştirilebilir. Dikkatli bir şekilde uygulandığında, eski ve yeni ağaçlar düğümlerinin çoğunu paylaşır. Bunu standart bir karma tablo ile yapamazsınız.
İkili bir ağacın aranması ve eklenmesi daha yavaştır, ancak iç içe geçmenin çok güzel bir özelliğine sahiptir, bu da temelde ağacın düğümleri arasında sıralı bir sırayla yineleme yapabileceğiniz anlamına gelir.
Bir karma tablonun girişlerini yinelemek pek bir anlam ifade etmiyor çünkü hepsi hafızaya dağılmış durumda.
Gönderen Kodlama Röportajı Cracking, 6th Edition
Hash tablosunu dengeli bir ikili arama ağacı (BST) ile uygulayabiliriz. Bu bize bir O (log n) arama süresi verir. Bunun avantajı, artık büyük bir dizi ayırmadığımız için potansiyel olarak daha az alan kullanmaktır. Ayrıca anahtarları sırayla yineleyebiliriz, bu bazen yararlı olabilir.
BST'ler aynı zamanda O (logn) zamanında "findPredecessor" ve "findSuccessor" işlemlerini (sonraki en küçük ve sonraki en büyük elemanları bulmak için) sağlar ve bu da çok kullanışlı işlemler olabilir. Hash Table o zaman verimliliğini sağlayamaz.
Verilere sıralı bir şekilde erişmek istiyorsanız, karma tabloya paralel olarak sıralı bir listenin korunması gerekir. İyi bir örnek .Net'teki Sözlük'tir. (bkz. http://msdn.microsoft.com/en-us/library/3fcwy8h6.aspx ).
Bu, yalnızca eklemeleri yavaşlatmakla kalmaz, aynı zamanda bir b-ağacından daha fazla miktarda bellek tüketir.
Ayrıca, bir b-ağacı sıralandığı için, sonuç aralıklarını bulmak veya birleştirme veya birleştirme yapmak kolaydır.
Aynı zamanda kullanıma da bağlıdır, Hash tam eşleşmeyi bulmaya izin verir. Bir aralık için sorgulama yapmak istiyorsanız, seçim BST'dir. Bir çok veriniz olduğunu varsayalım e1, e2, e3 ..... tr.
Karma tablo ile herhangi bir elemanı sabit zamanda bulabilirsiniz.
E41'den büyük ve e8'den küçük aralık değerlerini bulmak isterseniz, BST bunu hızlı bir şekilde bulabilir.
Önemli olan, bir çarpışmayı önlemek için kullanılan hash fonksiyonudur. Elbette bir çarpışmadan tamamen kaçınamayız, bu durumda zincirleme veya başka yöntemlere başvururuz. Bu, en kötü durumlarda geri çağırmanın artık sabit zaman olmasını sağlamaz.
Dolduktan sonra, hash tablosunun kova boyutunu artırması ve tüm öğeleri tekrar kopyalaması gerekir. Bu, BST üzerinde bulunmayan ek bir maliyettir.
Karma Tablolar indeksleme için iyi değildir. Bir aralık ararken, BST'ler daha iyidir. Çoğu veritabanı dizininin Karma Tablolar yerine B + ağaçlarını kullanmasının nedeni budur.
İkili arama ağaçları, anahtarların üzerinde tanımlanmış bir toplam sıraya (anahtarlar karşılaştırılabilir) sahipse ve sipariş bilgilerini korumak istiyorsanız, sözlüğü uygulamak için iyi bir seçimdir.
BST, sipariş bilgilerini koruduğu için, size hash tabloları kullanılarak (verimli bir şekilde) gerçekleştirilemeyen dört ek dinamik ayar işlemi sağlar. Bu işlemler şunlardır:
Her BST işleminde olduğu gibi tüm bu işlemler, O (H) 'nin zaman karmaşıklığına sahiptir. Ek olarak, saklanan tüm anahtarlar BST'de sıralı olarak kalır, böylece sırayla ağacı geçerek sıralı anahtar dizisini elde etmenizi sağlar.
Özetle, tek istediğiniz işlem ekleme, silme ve kaldırma ise, hash tablosu performansta (çoğu zaman) rakipsizdir. Ancak, yukarıda listelenen işlemlerden herhangi birini veya tümünü istiyorsanız, bir BST, tercihen kendi kendini dengeleyen bir BST kullanmalısınız.
Hash tablosunun ana avantajı, ~ = O (1) 'deki hemen hemen tüm opları yapmasıdır. Anlaması ve uygulaması çok kolaydır. Birçok "görüşme problemini" verimli bir şekilde çözer. Eğer bir kodlama röportajı kırmak istiyorsanız, hash table ;-) ile en iyi arkadaşlar edinin.
Bir hashmap, küme bir ilişkilendirilebilir dizidir. Dolayısıyla, girdi değerleri diziniz kümeler halinde havuzlanır. Açık bir adresleme şemasında, bir kova için bir işaretçiniz vardır ve bir kovaya her yeni bir değer eklediğinizde, kova içinde nerede boş alanlar olduğunu öğrenirsiniz. Bunu yapmanın birkaç yolu vardır - bölümün başlangıcından başlar ve her seferinde işaretçiyi artırır ve dolu olup olmadığını test edersiniz. Buna doğrusal problama denir. Ardından, bölmenin başlangıcı ile boş bir alan ararken her seferinde ikiye katladığınız veya geri aldığınız yer arasındaki farkı ikiye katladığınız add gibi ikili bir arama yapabilirsiniz. Buna ikinci dereceden araştırma denir. TAMAM. Şimdi bu iki yöntemdeki sorun şu ki, eğer paket sonraki paket adreslerine taşarsa, o zaman yapmanız gereken-
TAMAM. ama bağlantılı bir liste kullanırsanız böyle bir sorun olmamalı değil mi? Evet, bağlantılı listelerde bu problem yok. Her bir grubun bağlantılı bir listeyle başladığını düşünürsek ve bir pakette 100 öğe varsa, bağlantılı listenin sonuna ulaşmak için bu 100 öğeyi geçmeniz gerekir, dolayısıyla List.add (E Öğesi) zaman alacaktır.
Bağlantılı liste uygulamasının avantajı, açık adresleme uygulamasında olduğu gibi bellek ayırma işlemine ve tüm paketlerin O (N) aktarımına / kopyasına ihtiyacınız olmamasıdır.
Bu nedenle, O (N) işlemini en aza indirmenin yolu, uygulamayı bulma işlemlerinin O (log (N)) olduğu bir İkili Arama Ağacına dönüştürmektir ve öğeyi değerine göre konumuna eklersiniz. Bir BST'nin eklenen özelliği, sıralı olarak gelmesidir!
İkili arama ağaçları, dize anahtarlarıyla kullanıldığında daha hızlı olabilir. Özellikle dizeler uzun olduğunda.
Dizeler için hızlı olan (eşit olmadıklarında) daha az / daha büyük karşılaştırmaları kullanan ikili arama ağaçları. Böylece bir BST, bir dizi bulunamadığında hızlı bir şekilde yanıt verebilir. Bulunduğunda yalnızca bir tam karşılaştırma yapması gerekecektir.
Bir hash tablosunda. Dizenin karmasını hesaplamanız gerekir ve bu, karmayı hesaplamak için tüm baytlardan en az bir kez geçmeniz gerektiği anlamına gelir. Sonra yine eşleşen bir giriş bulunduğunda.