Hangi sıralama algoritması çoğunlukla sıralanmış verilerde en iyi sonucu verir?
Hangi sıralama algoritması çoğunlukla sıralanmış verilerde en iyi sonucu verir?
Yanıtlar:
Animasyonlu gifleri izlemek için son derece bilimsel bir metoda dayanarak Yerleştirme ve Kabarcık türlerinin iyi adaylar olduğunu söyleyebilirim.
Yalnızca birkaç öğe => SIRALAMA SIRALAMA
Öğeler çoğunlukla zaten sıralanmıştır => INSERTION SORT
En kötü senaryolar hakkında endişeli => HEAP SORT
İyi bir ortalama vaka sonucuyla ilgileniyor => QUICKSORT
Öğeler yoğun bir evrenden alınmıştır => KOVA SIRALAMA
Mümkün olduğunca az kod yazma isteği => INSERTION SORT
Timsort , " kısmen düzenlenmiş birçok dizide ( lg'den (N!) Daha az ve N-1 kadar az) karşılaştırılması gereken doğaüstü performans " ile uyumlu, kararlı, doğal bir birleşimdir ". Python'un yerleşiksort()
görünüşte iyi sonuçlarla bu algoritmayı bir süredir kullandı. Girişte, genellikle gerçek veri kümelerinde ortaya çıkan kısmen sıralı alt dizileri algılamak ve yararlanmak için özel olarak tasarlanmıştır. Gerçek dünyada karşılaştırmalar bir listedeki öğeleri takas etmekten çok daha pahalıdır, çünkü biri tipik olarak sadece işaretçileri değiştirir, bu da genellikle timsort'u mükemmel bir seçim yapar. Ancak, karşılaştırmalarınızın her zaman çok ucuz olduğunu biliyorsanız (örneğin, 32 bit tam sayıları sıralamak için bir oyuncak programı yazmak), daha iyi performans göstermesi muhtemel diğer algoritmalar vardır. Timsort'tan yararlanmanın en kolay yolu elbette Python kullanmaktır, ancak Python açık kaynak olduğundan kodu ödünç alabilirsiniz. Alternatif olarak, yukarıdaki açıklama kendi uygulamanızı yazmak için fazlasıyla ayrıntı içerir.
lg(n!)
neredeyse sıralanmış bir dizideki karşılaştırmalardan çok daha hızlı O(n)
! | @behrooz: Hiçbir karşılaştırma sıralamasının ortalamadan daha iyi bir durumu olamaz O(n log n)
ve lg(n!)
öyle değildir O(n log n)
. Bu nedenle timsort'un en kötü durumu asemptotik olarak diğer karşılaştırma türlerinden daha kötü değildir. Ayrıca, en iyi durumu diğer karşılaştırma türlerinden daha iyi veya eşittir.
Aşağıdaki davranışa sahip sıralama türü:
k
için 1..n
önce olup olmadığını kontrol edin el[k] >= el[k-1]
. Öyleyse, bir sonraki öğeye git. (Açıkçası ilk öğeyi atla.)1..k-1
, ekleme konumunu belirlemek için öğelerde ikili aramayı kullanın , ardından öğeleri üzerinde gezdirin. (Bunu yalnızca bir eşik değerin k>T
olduğu yerlerde yapabilirsiniz T
; küçük k
olanlarda bu aşırıdır.)Bu yöntem en az sayıda karşılaştırma yapar.
İçsel sıralamayı deneyin. http://en.wikipedia.org/wiki/Introsort
Quicksort tabanlıdır, ancak quicksort'un neredeyse sıralanmış listeler için sahip olduğu en kötü durum davranışını önler.
İşin püf noktası, bu sıralama algoritmasının, quicksort'un en kötü durum moduna girdiği ve yığın veya birleştirme sıralamasına geçtiği durumları algılamasıdır. Neredeyse sıralanan bölümler, bazı naif olmayan bölümleme yöntemi ile algılanır ve küçük bölümler, ekleme sıralaması kullanılarak işlenir.
Daha fazla kod ve karmaşıklık maliyeti için tüm büyük sıralama algoritmalarından en iyisini elde edersiniz. Ayrıca, verileriniz nasıl göründüğüne bakılmaksızın hiçbir zaman en kötü durum davranışıyla karşılaşmayacağınızdan emin olabilirsiniz.
Bir C ++ programcısıysanız std :: sort algoritmanızı kontrol edin. İçsel olarak içsel sıralama kullanabilir.
Splaysort , uyarlanabilir bir ikili ağaç türü olan splay ağaçlarına dayanan belirsiz bir sıralama yöntemidir . Splaysort sadece kısmen sıralanan veriler için değil, aynı zamanda kısmen ters sıralanan veriler veya gerçekten de önceden var olan herhangi bir sıraya sahip herhangi bir veri için iyidir. Genel durumda O (nlogn) ve verilerin bir şekilde sıralandığı durumda (ileri, geri, organ borusu, vb.) O (n) 'dir.
Ekleme sıralamasına göre en büyük avantajı, veriler hiç sıralanmadığında O (n ^ 2) davranışına dönmemesidir, bu nedenle kullanmadan önce verilerin kısmen sıralandığından kesinlikle emin olmanıza gerek yoktur. .
Dezavantajı, ihtiyaç duyduğu splay ağacı yapısının fazladan ek yükü ve ayrıca splay ağacını inşa etmek ve imha etmek için gereken süredir. Ancak, verilerin boyutuna ve beklediğiniz ön sıralama miktarına bağlı olarak, ek yük hızdaki artış için buna değebilir.
Splaysort üzerine bir makale Software - Practice & Experience'da yayınlandı.
Dijkstra'nın smoothsort zaten sıralanmış verilerde harika bir çeşittir. O (n lg n) en kötü durumda ve O (n) en iyi durumda çalışan bir yığın varyantıdır. Ben bir analiz yazdım , algoritmanın durumunda nasıl çalıştığını merak ediyoruz.
Doğal birleştirme, bunun için gerçekten iyi bir başka şeydir - girdiyi birden çok farklı sıralı aralığın birleşimi olarak ele alıp, sonra birleştirmek için birleştirme algoritmasını kullanarak çalışan aşağıdan yukarıya bir birleştirme çeşidi. Tüm giriş aralığı sıralanana kadar bu işlemi tekrarlayın. Veriler zaten sıralanmışsa ve O (n lg n) en kötü durumdaysa, O (n) zamanında çalışır. Çok zarif, ancak pratikte Timsort veya smoothsort gibi diğer uyarlanabilir türler kadar iyi değil.
Ekleme sıralaması zaman alır O (n + ters çevirme sayısı).
Bir ters bir çift (i, j)
şekildedir i < j && a[i] > a[j]
. Yani, sıra dışı bir çift.
"Neredeyse sıralanmış" olmanın bir ölçüsü, tersine çevirme sayısıdır - "neredeyse sıralanmış veriler", az sayıda tersine çevrilmiş veri anlamına gelebilir. Tersine çevrilme sayısının doğrusal olduğunu biliyorsanız (örneğin, sıralı bir listeye O (1) eleman eklediniz), ekleme sıralaması O (n) zaman alır.
Herkesin söylediği gibi, saf Quicksort'a dikkat edin - sıralanan veya neredeyse sıralanan verilerde O (N ^ 2) performansına sahip olabilir. Bununla birlikte, pivot seçimi için uygun bir algoritma ile (rastgele veya üç medyan - bkz . Quicksort için Pivot Seçme ), Quicksort hala akılcı çalışır.
Genel olarak, insert sıralama gibi algoritmaları seçme konusundaki zorluk, verinin Quicksort'un gerçekten daha hızlı olacağı sırada yeterince bozuk olmadığına karar vermektir.
Burada tüm cevapları varmış gibi davranmayacağım, çünkü gerçek cevaplara ulaşmak algoritmaları kodlamayı ve temsili veri örneklerine karşı profillemeyi gerektirebilir. Ama bütün akşam bu soruyu düşünüyordum ve işte şu ana kadar olan şey ve burada en iyi neyin işe yaradığına dair bazı tahminler var.
N toplam öğe sayısı, M sıra dışı sayı olsun.
Kabarcık sıralaması, tüm N öğelerinden 2 * M + 1 geçişleri gibi bir şey yapmak zorunda kalacak. M çok küçükse (0, 1, 2?), Bunun yenilmesi çok zor olacağını düşünüyorum.
M küçükse (log N'den daha az diyelim), ekleme sıralaması mükemmel ortalama performansa sahip olacaktır. Ancak, görmediğim bir hile yoksa, en kötü durum performansına sahip olacaktır. (Doğru? Siparişteki son öğe önce gelirse, görebildiğim kadarıyla her bir öğeyi eklemeniz gerekir, bu da performansı öldürür.) Bunun için daha güvenilir bir sıralama algoritması olduğunu tahmin ediyorum ama ne olduğunu bilmiyorum.
M daha büyükse (log N'ye eşit veya büyük diyelim), introspektif sıralama neredeyse kesinlikle en iyisidir.
Tüm bunlara istisna: Gerçekten hangi öğelerin sıralanmamış olduğunu önceden biliyorsanız, en iyi seçeneğiniz bu öğeleri çıkarmak, introspektif sıralama kullanarak sıralamak ve iki sıralı listeyi bir sıralı listede birleştirmektir. Hangi öğelerin bozuk olduğunu hızlı bir şekilde anlayabilseydiniz, bu da iyi bir genel çözüm olurdu - ancak bunu yapmanın basit bir yolunu bulamadım.
Diğer düşünceler (gece boyunca): M + 1 <N / M ise, sıralanan bir satırda N / M çalışması arayan listeyi tarayabilir ve ardından çıkışı bulmak için her iki yönde de bu çalışmayı genişletebilirsiniz. -sipariş öğeleri. Bu en fazla 2N karşılaştırması alacaktır. Daha sonra sıralanmamış öğeleri sıralayabilir ve iki listede sıralı birleştirme yapabilirsiniz. Toplam karşılaştırmalar 4N + M log2 (M) gibi bir şeyden daha az olmalıdır, ki bu herhangi bir özel olmayan sıralama rutinini yenecektir. (Daha da fazla düşündüm: bu düşündüğümden daha zor, ama yine de makul bir şekilde mümkün olduğunu düşünüyorum.)
Sorunun başka bir yorumu, birçok sıra dışı öğenin olabileceğidir, ancak listede bulunmaları gereken yerlere çok yakındırlar. (Sıralı bir listeden başlayıp diğer her öğeden sonra gelenle değiştirmeyi düşünün.) Bu durumda kabarcık sıralamasının çok iyi performans gösterdiğini düşünüyorum - Geçiş sayısının bir öğenin en uzaktaki yeri ile orantılı olacağını düşünüyorum. dır-dir. Her sıra dışı öğe bir ekleme işlemini tetikleyeceğinden, ekleme türü kötü çalışacaktır. İçsel sıralama veya bunun gibi bir şeyin de iyi çalışacağından şüpheleniyorum.
Algoritmaları, veri yapılarını veya yukarıdakilere bağlantısı olan herhangi bir şeyi sıralamak için özel bir uygulamaya ihtiyacınız varsa, size CodePlex'teki mükemmel "Veri Yapıları ve Algoritmalar" projesini önerebilir miyim ?
Tekerleği yeniden icat etmeden ihtiyacınız olan her şeye sahip olacak.
Sadece küçük tuzum.
Cevaplarda bu amaç için sıralama algoritmalarının bu güzel koleksiyonu, uygun olabilecek ve muhtemelen en az uygulama çabası gerektiren Gnome Sort'tan yoksundur .
düşünmek Heap deneyin. O (n lg n) çeşitlerinin en tutarlı olduğuna inanıyorum.
Kabarcık sıralaması (veya henüz daha güvenli, çift yönlü kabarcık sıralaması) çoğunlukla sıralı listeler için idealdir, ancak liste ayarlanmadığında (çok daha düşük bir başlangıç boşluğu boyutuna sahip) ayarlanmış bir tarak sıralama biraz daha hızlı olurdu. t Oldukça mükemmel bir şekilde sıralanmış. Tarak sıralaması kabarcık sıralamasında bozunur.
iyi kullanım durumuna bağlıdır. Hangi öğelerin değiştirildiğini biliyorsanız, çıkarma ve ekleme en iyi durumda olacaktır.
Kabarcık sıralama kesinlikle kazanan Radarda bir sonraki ekleme türü olurdu.
QuickSort'tan uzak durun - önceden sıralanmış veriler için çok verimsiz. Ekleme sıralama, mümkün olduğunca az değer taşıyarak neredeyse sıralanmış verileri iyi işler.