Gerçekten bir Fibonacci-Yığını etkili bir şekilde uygulayan var mı?


151

Herhangi biriniz hiç Fibonacci-Heap uyguladınız mı? Birkaç yıl önce yaptım, ancak dizi tabanlı BinHeaps kullanmaktan daha yavaş birkaç büyüklük emriydi.

O zamanlar bunu araştırmanın iddia ettiği kadar iyi olmadığı konusunda değerli bir ders olarak düşündüm. Bununla birlikte, birçok araştırma makalesi, bir Fibonacci-Heap kullanmaya dayanan algoritmalarının çalışma sürelerini iddia etmektedir.

Hiç verimli bir uygulama üretmeyi başardınız mı? Yoksa Fibonacci-Heap'in daha verimli olduğu kadar büyük veri kümeleriyle mi çalıştınız? Eğer öyleyse, bazı detaylar takdir edilecektir.


25
Bu algoritma adamlarının büyük sabitlerini her zaman büyük büyüklerinin arkasına sakladıklarını öğrenmediniz mi ?! :) Uygulamada, çoğu zaman, "n" şey asla "n0" bile yakın alır gibi görünüyor!
Mehrdad Afshari

Şimdi biliyorum. "Algoritmalara Giriş" kopyamı ilk aldığımda uyguladım. Ayrıca, işe yaramaz bir veri yapısı icat edecek biri için Tarjan'ı seçmedim, çünkü Splay Ağaçları aslında oldukça havalı.
mdm

mdm: Elbette işe yaramaz, ancak tıpkı küçük veri kümelerinde çabuk sıralama yapan ekleme sıralaması gibi, ikili yığınlar daha küçük sabitler nedeniyle daha iyi çalışabilir.
Mehrdad Afshari

1
Aslında, yığın için gereken program VLSI-yongalarında yönlendirme için Steiner-Ağaçları bulmaktı, bu yüzden veri setleri tam olarak küçük değildi. Ancak günümüzde (sıralama gibi basit şeyler hariç) her zaman daha basit algoritmayı veri setinde "kırılana" kullanırdım.
mdm

1
Buna cevabım aslında "evet". (Eh, bir kağıt üzerinde benim coauthor yaptı.) Şu anda kodu yok, bu yüzden aslında cevap vermeden önce daha fazla bilgi alırım. Grafiklerimize bakıldığında, F yığınlarının b yığınlarından daha az karşılaştırma yaptığını not ediyorum. Karşılaştırmanın ucuz olduğu bir şey mi kullanıyordunuz?
A. Rex

Yanıtlar:


136

Boost C ++ kütüphaneleri içinde Fibonacci yığınları bir uygulamasını içerir boost/pending/fibonacci_heap.hpp. Görünüşe göre bu dosya pending/yıllardır var ve benim tahminlerim tarafından asla kabul edilmeyecek. Ayrıca, bu uygulamada tanıdıklarım ve çok yönlü havalı adam Aaron Windsor tarafından düzeltilen hatalar oldu. Ne yazık ki, bu dosyanın çevrimiçi olarak bulabildiğim sürümlerinin çoğu (ve Ubuntu'nun libboost-dev paketindeki) sürümlerinde hala hatalar vardı; Subversion deposundan temiz bir sürüm çekmek zorunda kaldım .

Sürüm 1.49 Boost C ++ kütüphaneleri beri fibonacci yığın dahil olmak üzere birçok yeni yığın yapı ekledi.

Fibonacci yığınlarını ve ikili yığınları karşılaştırmak için dijkstra_shortest_paths.hpp'nin değiştirilmiş bir versiyonuna karşı dijkstra_heap_performance.cpp'yi derleyebildim . (Çizgidetypedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueue , değiştirme relaxediçin fibonacci.) İlk ve bu durumda Fibonacci ve ikili yığınları Fibonacci yığınları, genellikle önemsiz bir miktarı ile daha iyi performans ile, yaklaşık olarak aynı yerine, en iyi duruma derleme unuttum. Çok güçlü optimizasyonlarla derlendikten sonra, ikili yığınlar muazzam bir artış gösterdi. Testlerimde, Fibonacci yığınları, grafik inanılmaz derecede büyük ve yoğun olduğunda, örneğin:

Generating graph...10000 vertices, 20000000 edges.
Running Dijkstra's with binary heap...1.46 seconds.
Running Dijkstra's with Fibonacci heap...1.31 seconds.
Speedup = 1.1145.

Anladığım kadarıyla, bu Fibonacci yığınları ve ikili yığınlar arasındaki temel farklılıklara değiyor. İki veri yapısı arasındaki tek gerçek teorik fark, Fibonacci yığınlarının (amortismanlı) sabit sürede azaltma tuşunu desteklemesidir. Öte yandan, ikili yığınlar bir dizi olarak uygulamalarından büyük bir performans elde eder; açık bir işaretçi yapısı kullanmak, Fibonacci yığınlarının büyük bir performans isabeti çektiği anlamına gelir.

Bu nedenle, pratikte Fibonacci yığınlarından faydalanmak için , onları azalma_anahtarlarının inanılmaz sık olduğu bir uygulamada kullanmanız gerekir. Dijkstra açısından, alttaki grafiğin yoğun olduğu anlamına gelir. Bazı uygulamalar içsel olarak reduce_key-intense olabilir; Denemek istedimNagomochi-Ibaraki minimum kesim algoritmasını çünkü görünüşe göre bir sürü reduce_key üretiyor, ama bir zamanlama karşılaştırması çalışmak için çok fazla çaba oldu.

Uyarı : Yanlış bir şey yapmış olabilirim. Bu sonuçları kendiniz oluşturmayı deneyebilirsiniz.

Teorik not : Fibonacci yığınlarının reduce_key üzerindeki gelişmiş performansı, Dijkstra'nın çalışma süresi gibi teorik uygulamalar için önemlidir. Fibonacci yığınları ayrıca yerleştirme ve birleştirme üzerindeki ikili yığınlardan daha iyi performans gösterir (her ikisi de Fibonacci yığınları için itfa edilmiş sabit zamanlı). Ekleme esasen önemsizdir, çünkü Dijkstra'nın çalışma zamanını etkilemez ve ikili yığınları itfa edilmiş sabit zamanda da eklemek için değiştirmek oldukça kolaydır. Sabit zamanda birleştirme harika, ancak bu uygulama ile ilgili değil.

Kişisel not : Bir arkadaşım ve ben bir zamanlar, Fibonacci yığınlarının karmaşıklık olmadan (teorik) çalışma süresini çoğaltmaya çalışan yeni bir öncelik sırasını açıklayan bir makale yazdık. Makale asla yayınlanmadı, ancak yazarım ikili yapıları, Fibonacci yığınlarını ve veri yapılarını karşılaştırmak için kendi öncelik kuyruğumuzu uyguladı. Deney sonuçlarının grafikleri, Fibonacci'nin toplam karşılaştırmalar açısından hafifçe gerçekleştirilen ikili yığınları yığınladığını göstermektedir, bu da Fibonacci yığınlarının karşılaştırma maliyetinin ek yükü aştığı bir durumda daha iyi performans göstereceğini göstermektedir. Ne yazık ki, mevcut kodum yok ve muhtemelen durum karşılaştırmanızda ucuz, bu yüzden bu yorumlar alakalı ama doğrudan uygulanabilir değil.

Bu arada, Fibonacci yığınlarının çalışma zamanını kendi veri yapınızla eşleştirmeye çalışmanızı şiddetle tavsiye ederim. Fibonacci yığınlarını kendim yeniden keşfettiğimi fark ettim. Fibonacci yığınlarının tüm karmaşıklıklarının bazı rastgele fikirler olduğunu düşünmeden önce, ancak hepsinin doğal ve oldukça zorlandığını fark ettim.


Teşekkürler! Bu soru uzun zamandır aklımda duruyor. Steiner-Ağaçları denemeden önce aslında Dijkstra'ları Fibonacci-Heaps kullanarak uyguladım. Ancak, grafiklerim örneğinizden çok daha az yoğun olduğu görülüyor. Milyonlarca düğümleri vardı, ancak ortalama derecesi sadece 5-6 idi.
mdm

Fib Heap performansı, işlem dizisi yoluyla tahmin edilebilir. Fib Heap (Bin Heap'a karşı) ile daha hızlı sonuç veren bir Heap-heavy algoritması yazdım. Hile işi topluyordu. Herhangi bir işlemin sıklığına bakılmaksızın, fark burada yatmaktadır: DecreaseKey - ExtractMin - DecreaseKey - ExtractMin'e karşı DecreaseKey - DecreaseKey - ExtractMin - ExtractMin (devam ediyor)
Gaminic

İkincisi kabaca iki kat daha hızlı olacaktır, çünkü 2. ExtractMin neredeyse ücretsizdir. Algoritmamız, birçoğu atılan bir dizi Min elementi çıkarır; bir Bin Yığın üzerinde bir atık, ama bir Fib Yığın üzerinde daha iyi. Ne yazık ki bu, Heap tabanlı algoritmalar hakkında konuşurken insanların sağladığı karmaşıklığa açıkça yansımıyor. İtfa edilmiş sınırlarla, toplam karmaşıklık yalnızca # işlem * işlem karmaşıklığı değildir.
Gaminic

1
Yığınları ve / veya rahat yığınları eşleştirme şansı var mı?
Thomas Ahle

1
Sonuçlarınızın neden bu kadar yakın göründüğünden emin değilim, kendimi uyguladığım fibonacci yığınına karşı STL öncelikli_kullanımı kullandım ve ikili yığın testlerimde büyük bir farkla geride kaldı .
Nicholas Pipitone

33

Knuth, 1993 yılında Stanford Graphbase adlı kitabı için minimum yayılan ağaçlar için fibonacci yığını ve ikili yığınlar arasında bir karşılaştırma yaptı . Test ettiği grafik boyutlarında fibonacci'nin ikili yığınlardan 30 ila 60 derece daha yavaş, farklı yoğunluklarda 128 köşe noktası olduğunu buldu.

Kaynak kodu (tercihan Cı-, matematik ve TeX arasında çapraz CWEB veya) bölümünde MILES_SPAN olarak C olan.


1

feragat

Sonuçların oldukça benzer olduğunu ve "çalışma süresinin tamamen öbekten başka bir şeye hâkim olduğunu gösteriyor" (@Alpedar). Ancak kodda bununla ilgili hiçbir kanıt bulamadım. Kod açık olduğundan, testin sonucunu etkileyebilecek bir şey bulabilirseniz, lütfen bana bildirin.


Belki yanlış bir şey yaptım, ama A.Rex anwser karşılaştırma dayalı bir test yazdım :

  • Fibonacci-Öbek
  • D-Ary-yığın (4)
  • İkili-Yığın
  • Rahat-Öbek

Tüm yığınlar için yürütme süreleri (yalnızca tam grafikler için) çok yakındı. Test, 1000,2000,3000,4000,5000,6000,7000 ve 8000 köşeli tam grafikler için yapıldı. Her test için 50 rastgele grafik oluşturuldu ve çıktı her yığının ortalama süresidir:

Çıktı için üzgünüm, çok ayrıntılı değil çünkü metin dosyalarından bazı grafikler oluşturmak için gerekli.


Sonuçlar (saniye cinsinden):

yığın sonuç tablosu


4
Her durumda ne kadar kenar var? Tam olarak hangi algoritmayı çalıştırıyorsunuz? Ne ile uğraştığımızı bilmiyorsak, sonuçlarınız mantıklı değil.
kokx

Üzgünüm, tüm grafik tamamlandı, böylece her vaka için kenar sayısını hesaplayabilirsiniz. Ne demek "tam olarak kaçıyorsun". Masaların başındalar.
Guilherme Torres Castro

22
Bu, çalışma süresinin tamamen öbek dışında bir şey tarafından domine edildiğine benziyor (grafik veya bazı IO üretebilir). Neredeyse tamamen aynı sonuçlar inanılmaz.
Alpedar

2
Belki de zaman os başka bir şey hakim, ama eminim IO veya grafik üretimi değil. Neyse kaynak kodu mevcuttur ve birisi bir hata bulmak ve mesure düzeltmek ben çok memnun olacak.
Guilherme Torres Castro

Bu testler tamamen farklı bir şeyi ölçüyor gibi görünüyor. Yaptığınız test hakkında yorum yapabilir misiniz? Mesafeler Geometrik / Öklidiyse, tam bir grafikteki En Kısa Yol Probleminin O (1) olduğunu unutmayın.
Gaminic

0

Ayrıca Fibonacci yığını ile küçük bir deney yaptım. Detaylar için link: dijkstras-algoritması ile deneme . Sadece "Fibonacci yığın java" terimlerini araştırdım ve Fibonacci yığınının mevcut birkaç açık kaynaklı uygulamasını denedim. Bazılarının bazı performans sorunları var gibi görünüyor, ancak bazıları oldukça iyi. En azından, testimde saf ve ikili yığın PQ performansını atıyorlar. Belki de verimli olanı uygulamaya yardımcı olabilirler.

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.