Kırmızı-Siyah ağaçlar neden bu kadar popüler?


46

Göründüğüm her yerde veri yapıları kırmızı-siyah ağaçlar kullanılarak uygulanmaktadır ( std::setC ++ 'da, SortedDictionaryC #' da vs.)

Algoritmalar dersimde yeni (a, b), kırmızı-siyah ve AVL ağaçları kapladıktan sonra, dışarı çıktığım şey şu (profesörlere sormaktan, birkaç kitaptan bakmaktan ve biraz googling yapmaktan):

  • AVL ağaçları kırmızı-siyah ağaçlardan daha küçük ortalama derinliğe sahiptir ve bu nedenle AVL ağacında bir değer aramak sürekli olarak daha hızlıdır.
  • Kırmızı-siyah ağaçlar kendilerini dengelemek için AVL ağaçlarından daha az yapısal değişiklikler yapar, bu da ekleme / silme için potansiyel olarak daha hızlı olmalarını sağlar. Potansiyel olarak söylüyorum, çünkü bu, ağaçtaki yapısal değişimin maliyetine bağlı olacaktır, çünkü bu, çalışma süresine ve uygulamaya çok bağlıdır (ağaç değişmez olduğunda işlevsel bir dilde tamamen farklı olabilir mi?).

Çevrimiçi olarak AVL ve Kırmızı-siyah ağaçları karşılaştıran birçok kıyaslama var, ancak beni asıl vurgulayan, profesörümün temel olarak söylediği, genellikle iki şeyden birini yapacağınızı söylemek:

  • Performansı pek önemsemiyorsunuz, bu durumda çoğu durumda AVL ile Red-black arasındaki% 10-20 fark önemli değil.
  • Ya da gerçekten hem AVL hem de Red-black ağaçları hendek edeceğiniz ve B-ağaçları ile gideceğiniz performansı önemsiyorsunuz. hepsini bir sepete koyacağım.)

Bunun nedeni, bir B ağacının verileri daha kompakt bir şekilde bellekte depolamasıdır (bir düğüm birçok değer içerir), çok daha az önbellek özeti olmayacaktır. Ayrıca, kullanım durumuna göre uygulamada ince ayar yapabilir ve B ağacının sırasını CPU önbellek boyutuna vb. Göre ayarlayabilirsiniz.

Sorun şu ki, arama ağaçlarının farklı uygulamalarının gerçek hayattaki kullanımını gerçek modern donanım üzerinde gerçek anlamda analiz edecek herhangi bir kaynak bulamıyorum. Algoritmalar üzerine birçok kitap okudum ve farklı ağaç değişkenlerini bir araya getirecek bir şey bulamadım, birinin diğeriyle karşılaştırıldığında daha küçük ortalama derinliğe sahip olduğunu göstermek dışında (bu gerçekten ağacın nasıl davranacağını söylemez) gerçek programlarda.)

Söylendiği gibi, yukarıda belirtilenlere dayanarak Kırmızı-siyah ağaçların her yerde kullanılmasının özel bir nedeni var mı, B-ağaçlarının daha iyi performans göstermeleri mi gerekiyor? (bulabildiğim tek kriter olarak http://lh3lh3.users.sourceforge.net/udb.shtml dosyasını da gösteriyor , ancak bu özel bir uygulama konusu olabilir). Ya da herkesin Siyah Kara ağaçları kullanmasının sebebi, uygulanması oldukça kolay olduğu ya da farklı kelimelerle ifade etmenin zor olduğu için mi?

Ayrıca, biri işlevsel diller dünyasına geçtiğinde bu nasıl değişir? Hem Clojure hem de Scala'nın Clojure'un 32 dallanma faktörü kullandığı Hash dizi haritalanmış denemelerini kullandığı görülüyor .


8
Acınıza eklemek için, farklı türlerde arama ağaçları karşılaştıran makalelerin çoğu ideal deneylerden daha az performans gösterir.
Raphael

1
Bunu kendim hiç anlamadım, bence AVL ağaçlarının uygulanması kırmızı-siyah ağaçlardan daha kolaydır (yeniden dengeleme yaparken daha az vaka) ve performansta önemli bir fark görmedim.
Jordi Vermeulen

3
Stackoverflow'ta arkadaşlarımızla ilgili bir tartışma Neden std :: map kırmızı-siyah bir ağaç olarak uygulanıyor? .
Hendrik Oca

Yanıtlar:


10

Dan alıntı cevap “için AVL ağaçları ve kırmızı siyah Ağaçlarında kökünden dolaşımları sorusuna”

Kırmızı-siyah ağaçları da içeren, ancak AVL ağaçları da dahil olmayan bazı ikili arama ağaçları için, ağaca yapılan "düzeltmeler" aşağı doğru kolaylıkla tahmin edilebilir ve tek bir yukarıdan aşağıya geçiş sırasında gerçekleştirilebilir ve ikinci geçişe gerek kalmaz. Bu tür yerleştirme algoritmaları tipik olarak özyineleme yerine bir döngü ile uygulanır ve pratikte iki geçişli meslektaşlarından biraz daha hızlı çalışır.

Bu nedenle, bir RedBlack ağaç eki özyineleme olmadan gerçekleştirilebilir , işlev çağrısı önbelleğini aşarsanız bazı işlemcilerin özyinelemeleri çok pahalıdır (örneğin , Kayıt penceresinin kullanılması nedeniyle SPARC )

(Yazılımın Sparc'ta 10 kat daha hızlı çalıştığını, bir işlev çağrısını kaldırarak çalıştırdığımı gördüm; bu sık sık kod yolunun kayıt penceresi için çok derin olmasına neden oldu. Kayıt penceresinin ne kadar derin olacağını bilmiyorsunuz. Müşterinizin sistemi ve çağrı yığınının ne kadar altında "sıcak kod yolunda" olduğunuzu bilmiyorsunuz, özyineleme kullanmamak daha öngörülebilir hale geliyor.)

Ayrıca istifin tükenme riskini göze almamak bir avantajdır.


Ancak 2 ^ 32 düğümlü dengeli bir ağaç, yaklaşık 32 özyinelemeden fazlasını gerektirmez. Yığın kareniz 64 bayt olsa bile, bu 2 kb'den fazla yığın alanı değil. Bu gerçekten bir fark yaratabilir mi? Bundan şüpheliyim.
Björn Lindqvist

@ BjörnLindqvist, 1990'lardaki SPARC işlemcide sık sık 10 kat daha hızlı bir şekilde, 7 ile 6 arasındaki yığın derinliğinden ortak bir kod yolunu değiştirdim! .... o dosyaları tespit ettin nasıl yukarı Oku
Ian Ringrose

9

Son zamanlarda bu konuyu da araştırıyorum, bu yüzden burada bulgularım var, ancak veri yapılarında uzman olmadığımı unutmayın!

B-ağaçları hiç kullanamayacağın bazı durumlar var.

Öne çıkan bir vaka std::mapC ++ STL'dendir. Standart, var insertolan yinelemeleri geçersiz kılmayan bir standart gerektirir.

Hiçbir yineleyici veya referans geçersiz.

http://en.cppreference.com/w/cpp/container/map/insert

Bu, B-ağacı bir uygulama olarak ekler çünkü ekleme mevcut elemanların etrafında hareket eder.

Bir başka benzer kullanım durumu, izinsiz veri yapılandırmalarıdır. Yani, verilerinizi ağacın düğümü içine depolamak yerine, işaretçilerinizi yapınızın içindeki çocuklara / ebeveynlere depolarsınız:

// non intrusive
struct Node<T> {
    T value;
    Node<T> *left;
    Node<T> *right;
};
using WalrusList = Node<Walrus>;

// intrusive
struct Walrus {
    // Tree part
    Walrus *left;
    Walrus *right;

    // Object part
    int age;
    Food[4] stomach;
};

Sadece bir B-ağacı müdahaleci yapamazsınız, çünkü sadece bir işaretçi veri yapısı değildir.

Saldırgan kırmızı-siyah ağaçlar, örneğin, serbest bellek bloklarını yönetmek için jemalloc'ta kullanılır . Bu aynı zamanda Linux çekirdeğindeki popüler bir veri yapısıdır.

Ayrıca "tek geçişli kuyruk özyinelemeli" uygulamanın, değişken bir veri yapısı olarak kırmızı siyah ağaç popülaritesinin nedeni olmadığına inanıyorum .

kütükn

Ö(1)

Ö(1)

Açık veri yapılarında açıklanan değişken ana işaretçiler, yerleştirme için özyinelemeli bir geçiş ve sabitlemeler için yinelemeli bir döngü yukarı geçişi kullanır. Özyinelemeli çağrılar kuyruk konumlarındadır ve derleyiciler bunu bir döngüye göre optimize eder (bunu Rust'ta kontrol ettim).

Ö(1)


3

Evet, bu yetkili bir cevap değil, ne zaman dengeli bir ikili arama ağacını kodlamam gerektiğinde, bu kırmızı-siyah bir ağaç. Bunun birkaç nedeni var:

1) Ortalama yerleştirme maliyeti, kırmızı-siyah ağaçlar için (aramanız gerekmiyorsa), AVL ağaçları için logaritmik ise sabittir. Ayrıca, en fazla bir karmaşık yeniden yapılandırma içermektedir. En kötü durumda hala O (log N), fakat bu sadece basit renklendirme.

2) Her düğüm için yalnızca 1 bit ek bilgi gerektirirler ve bunu sık sık ücretsiz almanın bir yolunu bulabilirsiniz.

3) Bunu çok sık yapmak zorunda değilim, bu yüzden her yaptığımda tekrar tekrar nasıl yapılacağını bulmak zorundayım. Basit kurallar ve 2-4 ağaçla yazışmalar , kod her zaman karmaşık olsa da, her zaman kolay görünmesini sağlar . Hala bir gün kodun basit olacağını umuyorum.

4) Kırmızı-siyah ağacın karşılık gelen 2-4 ağaç düğümünü ayırma ve orta anahtarı sadece renklendirme yoluyla ana 2-4 düğüme yerleştirme şekli süper zarif. Sadece yapmayı seviyorum.


0

Kırmızı-siyah veya AVL ağaçları, anahtar uzun olduğunda veya başka bir nedenden dolayı bir anahtarın taşınması pahalı olduğunda B-ağaçları ve benzerlerine göre bir avantaja sahiptir.

std::setBir dizi performans nedeniyle büyük bir projeye kendi alternatifimi yarattım . AVL'yi kırmızı-siyah üzerinden performans nedenleriyle seçtim (ancak bu küçük performans iyileştirme std :: set yerine kendi yöntemimi kullanmak için bir neden değildi). “Anahtar” ın karmaşık ve taşınması zor olması önemli bir faktördü. (A, b) ağaçları, tuşların önünde bir başka dolaylı seviyeye ihtiyaç duyarsanız hala mantıklı mı? AVL ve kırmızı-siyah ağaçlar, tuşları hareket ettirmeden yeniden yapılandırılabilir, böylece anahtarların taşınması pahalı olduğunda bu avantajı sağlar.


İronik olarak, kırmızı-siyah ağaçlar "sadece" (a, b) ağaçlarının özel bir durumudur, bu yüzden konu parametrelerin titremesine mi düşüyor? (cc @Gilles)
Raphael
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.