Collections.sort neden hızlı sıralama yerine birleştirme sıralaması kullanıyor?


101

Hızlı sıralamanın en hızlı sıralama algoritması olduğunu biliyoruz.

JDK6 collections.sort, hızlı sıralama yerine birleştirme sıralama algoritmasını kullanır. Ancak Arrays.sort, hızlı sıralama algoritması kullanır.

Collections.sort'un hızlı sıralama yerine birleştirme sıralaması kullanmasının nedeni nedir?


3
Bir JDK yazarının yanıtlamasını sağlayamazsanız, elde edeceğiniz tek şey tahmin çalışmasıdır. Gerçek bir soru değil.
Lorne Markisi 13

4
@EJP İyi bir nokta, ama kesinlikle "Yapıcı değil" doğru kapanış nedeni. Buradaki sorunun ne olduğu bana açık.
Duncan Jones

2
Çünkü Java adamları bunu böyle yapmaya karar verdiler. Onlara sor. Sanırım burada meşru bir cevap alamazsınız. Ve hızlı sıralama en iyisi değil . Sadece jenerik kullanım için en iyisidir .
Adam Arold 13

4
Bir tahmin: Quicksort kararlı değil, Mergesort. İlkel öğeler için, kararlı / kararlı olmayan sıralama önemsizdir, olabilecek nesneler için (veya en azından, kararsız bir türe karşı hatalar alabilirsiniz).
parsifal

2
@EJP, JDK yazarlarının niyetlerini halka açık olmaktan alıkoyan hiçbir şey yok. Herkese açık olduğunda, yazarın cevap vermesine ihtiyacımız yok. Aslında, bir JDK yazarı cevap vermeden bile tahmin edilmekten daha fazlası olan bir cevap almak mümkün.
Pacerier

Yanıtlar:


188

Kuvvetle muhtemel Josh Bloch dan § :

Bu yöntemleri ben yazdım, bu yüzden cevap vermeye yetkili olduğumu düşünüyorum. Tek bir en iyi sıralama algoritması olmadığı doğrudur. QuickSort, birleştirme sıralaması ile karşılaştırıldığında iki büyük eksikliğe sahiptir:

  1. Kararlı değil (parsifal'in belirttiği gibi).

  2. N log n performansını garanti etmez ; patolojik girdilerde ikinci dereceden performansa düşebilir.

Kararlılık, (değer) eşitliğinden farklı bir kimlik kavramı olmadığından, ilkel tipler için bir sorun değildir. Ve ikinci dereceden davranış olasılığı, Bentely ve McIlroy'un uygulaması (veya daha sonra Dual Pivot Quicksort için ) için pratikte bir problem olarak görülmedi , bu yüzden bu QuickSort varyantları ilkel türler için kullanıldı.

İstikrar, rastgele nesneleri sıralarken çok önemlidir. Örneğin, e-posta mesajlarını temsil eden nesneleriniz olduğunu ve bunları önce tarihe, sonra gönderene göre sıraladığınızı varsayalım. Her göndericide tarihe göre sıralanmalarını bekliyorsunuz, ancak bu yalnızca sıralama kararlıysa doğru olacaktır. Bu nedenle, nesne referanslarını sıralamak için kararlı bir sıralama (Birleştirme Sıralaması) sağlamayı seçtik. (Teknik açıdan konuşursak, birden çok sıralı kararlı sıralama, sıralamaların tersi sırasına göre anahtarlar üzerinde bir sözlükbilimsel sıralama ile sonuçlanır: son sıralama, en önemli alt anahtarı belirler.)

Birleştirme Sıralamanın , girdi ne olursa olsun n log n (zaman) performansını garanti etmesi güzel bir yan avantajıdır . Elbette bir dezavantajı var: hızlı sıralama "yerinde" bir sıralamadır: sadece log n harici alan gerektirir (çağrı yığınını korumak için). Öte yandan, birleştirme, sıralama, O (n) dış alan gerektirir. TimSort varyantı (Java SE 6'da tanıtıldı), giriş dizisi neredeyse sıralıysa, önemli ölçüde daha az alan (O (k)) gerektirir.

Ayrıca aşağıdakiler de önemlidir:

Java.util.Arrays.sort tarafından ve (dolaylı olarak) java.util.Collections.sort tarafından nesne referanslarını sıralamak için kullanılan algoritma, "değiştirilmiş bir birleştirme sıralamasıdır (alt alt listedeki en yüksek öğe şundan küçükse birleştirme atlanır yüksek alt listedeki en düşük öğe). " O (n log n) performansını garanti eden ve O (n) ekstra alan gerektiren oldukça hızlı ve kararlı bir türdür. O günlerde (1997'de Joshua Bloch tarafından yazılmıştır), iyi bir seçimdi, ancak bugün çok daha iyisini yapabiliriz.

2003'ten beri, Python'un liste sıralaması, zaman sıralaması olarak bilinen bir algoritma kullanıyor (bunu yazan Tim Peters'ın ardından). Rastgele dizilerde çalıştırıldığında geleneksel bir birleştirme sıralamasıyla karşılaştırılabilir performans sunarken, kısmen sıralı dizilerde çalışırken n log (n) karşılaştırmasından çok daha azını gerektiren kararlı, uyarlanabilir, yinelemeli bir birleştirme sıralamasıdır. Tüm uygun birleştirme gibi zaman sıralaması kararlıdır ve O (n log n) zamanında çalışır (en kötü durum). En kötü durumda, timsort n / 2 nesne başvuruları için geçici depolama alanı gerektirir; en iyi durumda, yalnızca küçük bir sabit alan gerektirir. Bunu, n nesne referansı için her zaman fazladan alan gerektiren ve n log n'yi yalnızca neredeyse sıralanmış listelerde yenen mevcut uygulama ile karşılaştırın.

Timsort burada ayrıntılı olarak açıklanmıştır: http://svn.python.org/projects/python/trunk/Objects/listsort.txt .

Tim Peters'ın orijinal uygulaması C'de yazılmıştır. Joshua Bloch, onu C'den Java'ya taşıdı ve son test edildi, karşılaştırmalı değerlendirildi ve ortaya çıkan kodu kapsamlı bir şekilde ayarladı. Ortaya çıkan kod, java.util.Arrays.sort için açılan bir alternatiftir. Yüksek düzeyde sıralı verilerde, bu kod mevcut uygulamadan (HotSpot sunucu sanal makinesinde) 25 kat daha hızlı çalışabilir. Rastgele verilerde, eski ve yeni uygulamaların hızları karşılaştırılabilir. Çok kısa listeler için, yeni uygulama, rastgele verilerde bile eskisine göre önemli ölçüde daha hızlıdır (çünkü gereksiz veri kopyalamasını önler).

Ayrıca bkz . Yöntem Dizileri için Java 7 Tim Sort'u kullanıyor mu? .

Tek bir "en iyi" seçenek yoktur. Diğer birçok şeyde olduğu gibi, bu değiş tokuşlarla ilgilidir.

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.