Hangi sıralama algoritması çoğunlukla sıralanmış verilerde en iyi sonucu verir? [kapalı]


174

Hangi sıralama algoritması çoğunlukla sıralanmış verilerde en iyi sonucu verir?


Bağlam eksikliğinden tahmin etmek - ara sonuçları diske dökmek zorunda kalmadan bellek içi bir sıralama mı soruyorsunuz?
Jonathan Leffler

1
Bu animasyonlara göre ekleme sıralama en çok sıralanmış verilerde en iyi sonucu verir.
dopple

Yanıtlar:


259

Animasyonlu gifleri izlemek için son derece bilimsel bir metoda dayanarak Yerleştirme ve Kabarcık türlerinin iyi adaylar olduğunu söyleyebilirim.


19
Bu arada mükemmel bir bağlantı, kudos ve bir +1
09:59

5
Kabarcık sıralaması korkunç. Her zaman O (n ^ 2) 'dir. En azından doğru olması için cevabından çıkar lütfen.
jjnguy

79
jjnguy, bu sadece yanlış. Bence algoritma sınıfınızı tekrar almanız gerekiyor. Neredeyse sıralanmış verilerde (uyarlanabilir durum) O (N) 'dir. Ancak, verilerden 2 geçiş alır ve Ekleme, neredeyse sıralanmış veriler için yalnızca 1 alır ve bu da Eklemeyi kazanan yapar. Kabarcık yine de iyi
mmcdole

3
Verileriniz neredeyse hiç sıralanmazsa, performans gerçekten kötüleşir. Yine de şahsen kullanmam.
Blorgbeard

5
Denediğimde bu bağlantı koptu. Bunun yerine şunu deneyin: sorting-algorithms.com
Michael La Voie

107

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


1
Tam olarak aradığım cevap bu, kitap okuyorum ama belirli durumlarda alogorithms seçimi için net bir açıklama bulamıyorum, lütfen bunu ayrıntılı bir şekilde açıklayabilir veya bağlantı kurabilirim. biraz daha mı? Teşekkürler
Simran kaur

9
"Veriler zaten başka bir kritere göre sıralandı => MERGE SORT"
Jim Hunziker

30

timsort

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.


16
log (n!) Ο (n * log (n)) 'dir, bu nedenle "doğaüstü" değildir.
jfs


log (n!) hızlı değil. wolframalpha.com/input/?i=plot[log(N!) , {N, 0,1000}]
Behrooz

9
@JF Sebastian: Timsort, 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.
Artelius

3
Timsort en kötü durumda hala O (nlogn), ancak iyi durumları oldukça hoş. İşte bir karşılaştırma bazı grafikler ile verilmiştir: stromberg.dnsalias.org/~strombrg/sort-comparison Cython içinde timsort yaklaşık olarak hızlı Python'un C. timsort inşa olarak olmadığını Not
user1277476

19

Aşağıdaki davranışa sahip sıralama türü:

  1. Yuvalardaki her eleman kiç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.)
  2. Değilse 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>Tolduğu yerlerde yapabilirsiniz T; küçük kolanlarda bu aşırıdır.)

Bu yöntem en az sayıda karşılaştırma yapar.


Bence ayrıştırılmamış elemanların sayısı çok azsa (bir veya iki gibi) kabarcık sıralaması bunu yenebilir, ancak genel olarak bu muhtemelen en iyi çözüm olarak bana çarpıyor.
Sol

Adım 1 nedeniyle, zaten sıralanan herhangi bir öğe için tam olarak bir karşılaştırma ve sıfır veri taşıma vardır, ki bu kesinlikle yapabileceğiniz en iyisidir. Adım 2, geliştirebileceğiniz adımdır, ancak kabarcık aynı sayıda öğeyi hareket ettirir ve uygulamanıza bağlı olarak daha fazla karşılaştırmaya sahip olabilir .
Jason Cohen

Aslında, daha fazla düşündüğümde kabarcık türünün düşündüğümden daha güçlü olduğunu düşünüyorum. Aslında oldukça zor bir soru. Örneğin, en son olması gereken öğe dışında listenin tamamen sıralandığı durumu ele alırsanız, kabarcık sıralaması sizin tanımladığınızdan çok daha iyi performans gösterir.
Sol

Bunu uygulamaya çalıştım, ancak ikili arama, öğeyi eklemek için tüm bloğu hareket ettirmeniz gerektiğinden çok fazla bir gelişme değil. 2xrange yerine range + logb (range) elde edersiniz.
bu

11

İç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.


7

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ı.



5

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.


diğer sıralama algoritmalarına kıyasla smoothsort'un çalışma zamanı sabitleri nelerdir? (örn. aynı veriler için çalışma zamanı (smoothsort) / çalışma zamanı (insertionsort))
Arne Babenhauserheide

4

Öğeler zaten sıralanmışsa veya yalnızca birkaç öğe varsa, Ekleme Sıralaması için mükemmel bir kullanım örneği olacaktır!


3

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.


2

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.


2

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.


1

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.


1

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 .


0

Ekleme sıralaması, sıralı girişte en iyi O (n) harfidir. Ve çoğunlukla sıralanmış giriş (çok hızlı sıralama daha iyi) çok yakın.


0

düşünmek Heap deneyin. O (n lg n) çeşitlerinin en tutarlı olduğuna inanıyorum.


Tutarlılık burada endişe verici değildir. Yığın sıralı verilerde bile O (n lg n) verir ve gerçekten uyarlanabilir değildir. Geçerli seçenekler şunlar olabilir: Ekleme sıralaması, Timsort ve Bubblesort.
Max

0

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.


0

iyi kullanım durumuna bağlıdır. Hangi öğelerin değiştirildiğini biliyorsanız, çıkarma ve ekleme en iyi durumda olacaktır.


1
Bu "endişe duyduğum kadarıyla" algoritma verimliliği testi günümü aydınlatıyor :) Ciddi olmak, "kaldır ve ekle" yazarken Ekleme Sıralaması (daha önceki cevaplarda zaten belirtilmişti) anlamına mı geliyordu yoksa yeni bir algoritma mı? Öyleyse, lütfen cevabınızı genişletin.
yoniLavi

0

Kabarcık sıralama kesinlikle kazanan Radarda bir sonraki ekleme türü olurdu.


4
cevabınızı bir açıklama ile yayınlayın;

1
Yinelemeleri önlemek için göndermeden önce mevcut cevaplara göz atmanızı öneririm.
angainor

-1

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.


-1 Quicksort'un her endüstriyel uygulaması makul bir pivot seçimine sahiptir
Stephan Eggermont

1
Evet, ama pahalı olmadığı sürece hiçbir pivot seçimi mükemmel.
user1277476
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.