RB ağacı, B-Ağacı veya AVL ağacı ne zaman seçilir?


88

Bir programcı olarak ne zaman bir RB ağacı, B ağacı veya bir AVL ağacı kullanmayı düşünmeliyim? Seçime karar vermeden önce dikkate alınması gereken kilit noktalar nelerdir?

Biri lütfen her ağaç yapısı için bir senaryo ile neden diğerlerine göre seçildiğini kilit noktalara atıfta bulabilir mi?


10
Biri için bu soruyu takdir ediyorum - şu anda fastutil IntAVLTreeSet ve IntRBTreeSet seçenekleriyle sunuluyor.
Yang

Yanıtlar:


115

Bunu bir tutam tuzla al:

Binlerce öğeyi yönetirken ve bunları bir diskten veya yavaş bir depolama ortamından sayfalandırırken B-ağacı.

Ağaç üzerinde oldukça sık ekleme, silme ve geri alma işlemleri yaparken RB ağacı.

Eklemeleriniz ve silmeleriniz geri getirmelerinize göre seyrek olduğunda AVL ağacı.


34
Biraz daha ayrıntı eklemek gerekirse: B-ağaçları, çok sayıda kayıt tutmasına izin veren ancak yine de kısa boylu bir ağacı koruyan değişken sayıda çocuğa sahip olabilir. RB Ağacı, yeniden dengeleme konusunda daha az katı kurallara sahiptir, bu da eklemeleri / silmeleri AVL ağacından daha hızlı hale getirir. Tersine, AVL ağacı daha sıkı bir şekilde dengelidir, bu nedenle aramalar RB ağacından daha hızlıdır.
pschang

RB ağaçları aynı zamanda yeniden dengelemede daha iyi performansa O (1) sahiptir, bu da onları geri alma ve ileri geri alma ile kalıcı veri yapıları için daha uygun hale getirir.

20

B + ağaçlarının, ana bellekte bile iyi bir genel amaçlı sıralı kapsayıcı veri yapısı olduğunu düşünüyorum. Sanal bellek bir sorun olmasa bile, önbellek dostu olma durumu genellikle böyledir ve B + ağaçları sıralı erişim için özellikle iyidir - bağlantılı bir listeyle aynı asimptotik performans, ancak basit bir diziye yakın önbellek kolaylığı ile. Bütün bunlar ve O (log n) arama, ekleme ve silme.

Bununla birlikte, B + ağaçlarının sorunları vardır - örneğin ekleme / silme işlemi yaptığınızda düğümler içinde hareket eden öğeler, bu öğelere yönelik işaretçileri geçersiz kılar. "İmleç bakımı" yapan bir kapsayıcı kitaplığım var - imleçler kendilerini şu anda bağlantılı bir listede referans verdikleri yaprak düğüme iliştiriyor, böylece otomatik olarak düzeltilebilir veya geçersiz kılınabilirler. Nadiren bir veya ikiden fazla imleç olduğu için iyi çalışıyor - ama yine de fazladan bir iş.

Başka bir şey de, B + ağacının aslında sadece bu olmasıdır. İhtiyaç duyup duymadığınıza bağlı olarak yaprak olmayan düğümleri çıkarabilir veya yeniden oluşturabilirsiniz, ancak ikili ağaç düğümleriyle çok daha fazla esneklik elde edersiniz. İkili ağaç, bağlantılı bir listeye dönüştürülebilir ve düğümleri kopyalamadan geri döndürülebilir - sadece işaretçileri değiştirirsiniz ve şimdi ona farklı bir veri yapısı olarak davrandığınızı unutmayın. Diğer şeylerin yanı sıra, bu, ağaçları birleştirirken oldukça kolay O (n) elde edeceğiniz anlamına gelir - her iki ağacı da listelere dönüştürün, birleştirin, sonra tekrar bir ağaca dönüştürün.

Yine başka bir şey de bellek ayırma ve serbest bırakmadır. İkili bir ağaçta bu, algoritmalardan ayrılabilir - kullanıcı bir düğüm oluşturabilir, ardından ekleme algoritmasını çağırabilir ve silenler düğümleri çıkarabilir (bunları ağaçtan ayırın, ancak belleği boşaltmayın). Bir B-ağacında veya B + ağacında, bu açıkça çalışmaz - veriler çok öğeli bir düğümde yaşayacaktır. Kaç yeni düğüme ihtiyaç olduğunu ve bunların tahsis edilebileceğini anlayana kadar düğümleri değiştirmeden operasyonu "planlayan" ekleme yöntemleri yazmak bir zorluktur.

Kırmızı siyah mı AVL mi? Bunun büyük bir fark yaratacağından emin değilim. Kendi kütüphanemde, düğümleri işlemek için, çift bağlantılı listeler için yöntemler, basit ikili ağaçlar, yayvan ağaçlar, kırmızı-siyah ağaçlar ve çeşitli dönüştürmeler dahil olmak üzere ağaç ağaçları ile birlikte, politika tabanlı bir "araç" sınıfı var. Bu yöntemlerden bazıları sadece bir ara sıkıldığım için uygulandı. Treap yöntemlerini test ettiğimden bile emin değilim. AVL yerine kırmızı-siyah ağaçları seçmemin sebebi, kişisel olarak algoritmaları daha iyi anlıyorum - ki bu daha basit oldukları anlamına gelmez, sadece onlara daha aşina olduğum bir tarih şansı.

Son bir şey - B + ağaç kaplarımı yalnızca bir deney olarak geliştirdim. Aslında hiç bitmeyen deneylerden biri ama başkalarını tekrar etmeye teşvik edeceğim bir şey değil. İhtiyacınız olan tek şey sıralı bir kapsa, en iyi cevap mevcut kitaplığınızın sağladığını kullanmaktır - örneğin C ++ 'da std :: map vb. Kitaplığım yıllar içinde gelişti, kararlı hale getirmek epey zaman aldı ve nispeten yakın zamanda, teknik olarak taşınabilir olmadığını keşfettim (WRT'nin dışında biraz tanımlanmamış davranışa bağlı olarak).



0

Veri yapılarını seçerken, aşağıdaki gibi faktörlerden vazgeçersiniz:

  • geri alma hızı v güncelleme hızı
  • yapının en kötü durum işlemleriyle ne kadar iyi başa çıktığı, örneğin sıralı bir sırada gelen kayıtların eklenmesi
  • boşa alan

Robert Harvey'in atıfta bulunduğu Wikipedia makalelerini okuyarak başlayabilirim.

Pragmatik olarak, Java gibi dillerde çalışırken ortalama bir programcı, sağlanan koleksiyon sınıflarını kullanma eğilimindedir. Bir performans ayarlama faaliyetinde koleksiyon performansının sorunlu olduğu keşfedilirse, o zaman alternatif uygulamalar araştırılabilir. Bu, nadiren iş odaklı bir geliştirmenin dikkate alması gereken ilk şeydir. Bu tür veri yapılarını elle uygulamaya ihtiyaç duyulması son derece nadirdir, genellikle kullanılabilecek kütüphaneler vardır.


1
Adil olmak gerekirse, OP sordu when should I consider using, hayır when should I consider implementing. Son paragraf doğru olsa da bu soru bağlamında pek bir değer sağlamaz. Kütüphanelerde bile, iş gereksinimlerinize en uygun yapıyı etkili bir şekilde seçmek için algoritmaları anlamanız gerekir.
Dan Bechard
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.