Max neden sıralamadan daha yavaş?


92

Bunun Python 2 ve 3'teki fonksiyondan maxdaha yavaş olduğunu buldum sort.

Python 2

$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 239 usec per loop
$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'max(a)'        
1000 loops, best of 3: 342 usec per loop

Python 3

$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 252 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a)'
1000 loops, best of 3: 371 usec per loop

Neden olduğu max ( O(n)daha az) daha yavaş sortfonksiyonu ( O(nlogn))?


3
Python 2 analizini bir kez çalıştırdınız ve Python 3 kodu tamamen aynı.
erip

9
a.sort()yerinde çalışır. Deneyinsorted(a)
Andrea Corbellini

Düzelttiyseniz, düzeltmek için yaptığınız şeyi geri gönderin, lütfen.
Pretzel

4
@Pretzel OP, sorunun çözüldüğü değil, gönderinin düzenlendiği anlamına gelir.
erip

2
@WeizhongTu ama sortsıralar ve asonsuza kadar sıralanır
njzk2

Yanıtlar:


125

timeitModülü Python'da kullanırken çok dikkatli olmalısınız .

python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'

Burada başlatma kodu rastgele bir dizi üretmek için bir kez çalışır a. Ardından kodun geri kalanı birkaç kez çalıştırılır. İlk kez diziyi sıralar, ancak her seferinde sıralama yöntemini önceden sıralanmış bir dizide çağırırsınız. Yalnızca en hızlı zaman döndürülür, bu nedenle Python'un önceden sıralanmış bir diziyi sıralamak için ne kadar sürdüğünü gerçekten hesaplıyorsunuz.

Python'un sıralama algoritmasının bir parçası, dizinin zaten kısmen veya tamamen sıralandığını tespit etmektir. Tamamen sıralandığında, bunu algılamak için diziyi bir kez taraması gerekir ve sonra durur.

Bunun yerine denediyseniz:

python -m timeit -s 'import random;a=range(100000);random.shuffle(a)' 'sorted(a)[-1]'

daha sonra sıralama her zamanlama döngüsünde gerçekleşir ve bir diziyi sıralama süresinin, yalnızca maksimum değeri bulmaktan çok daha uzun olduğunu görebilirsiniz.

Düzenleme: @ skyking'in cevabı , açıklanmadan bıraktığım kısmı açıklıyor: a.sort()bir liste üzerinde çalıştığını bilir, böylece öğelere doğrudan erişebilir. max(a)herhangi bir rasgele yinelenebilir üzerinde çalışır, bu nedenle genel yinelemeyi kullanmak zorundadır.


10
İyi yakalama. Yorumlayıcı durumunun kod çalıştırmaları boyunca korunduğunu hiç fark etmedim. Şimdi geçmişte kaç tane hatalı kıyaslama yaptığımı merak ediyorum. : -}
Frerich Raabe

1
Bu benim için çok açıktı. Ancak, önceden sıralanmış bir diziyi sıralasanız bile tüm öğeleri kontrol etmeniz gerektiğine dikkat edin. Bu da maksimuma ulaşmak kadar iş ... Bana göre bu yarım cevap gibi görünüyor.
Karoly Horvath

2
@KarolyHorvath, haklısın. Sanırım @skyking cevabın diğer yarısını aldı: a.sort()bir liste üzerinde çalıştığını biliyor, böylece öğelere doğrudan erişebilir. max(a)jenerik yinelemeyi kullanmak için rastgele bir dizi üzerinde çalışır.
Duncan

1
@KarolyHorvath, belki dal tahmini, sıralanmış bir diziyi tekrar tekrar sıralamanın neden daha hızlı olduğunu açıklayabilir: stackoverflow.com/a/11227902/4600
marcospereira

1
@JuniorCompressor listsort.txt, "Birçok türde kısmen sıralı dizilerde doğaüstü performansa sahip (lg (N!) Karşılaştırmalarından daha az ve N-1 kadar az)" açıklıyor ve ardından her türlü kanlı optimizasyonu açıklamaya devam ediyor. Sanırım yapamayan pek çok varsayımda maxbulunabilir, yani sıralama asimptotik olarak daha hızlı değildir.
Frerich Raabe

86

Öncelikle şunu unutmayın: max() yineleyici protokolünü kullanır iken, list.sort()kullanım ad-hoc kodu . Açıkçası, bir yineleyici kullanmak önemli bir ek yüktür, bu yüzden zamanlamalardaki bu farkı gözlemliyorsunuz.

Ancak bunun dışında testleriniz adil değil. a.sort()Aynı listede birden çok kez koşuyorsunuz . Python tarafından kullanılan algoritma özellikle hızlı zaten olacak şekilde tasarlanmıştır (kısmen) veri kriteri. Testleriniz, algoritmanın işini iyi yaptığını söylüyor.

Bunlar adil testlerdir:

$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a[:])'
1000 loops, best of 3: 227 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a[:].sort()'
100 loops, best of 3: 2.28 msec per loop

Burada her seferinde listenin bir kopyasını oluşturuyorum. Gördüğünüz gibi, sonuçların büyüklük sıralaması farklıdır: beklediğimiz gibi mikro ve milisaniyeler.

Ve unutmayın: büyük-Oh bir üst sınırı belirtir! Python'un sıralama algoritmasının alt sınırı Ω ( n ) 'dir. O ( n log n ) olmak otomatik olarak her çalıştırmanın n log n ile orantılı bir süre alacağı anlamına gelmez . O ( n ) algoritmasından daha yavaş olması gerektiği anlamına bile gelmez , ama bu başka bir hikaye. Anlaşılması gereken önemli olan, bazı uygun durumlarda, bir O ( n log n ) algoritmasının O ( n ) veya daha kısa sürede çalışabileceğidir .


31

Bunun nedeni olabilir l.sortüyesidir listederken maxjenerik fonksiyonudur. Bu araçlar l.sortdahili temsiliyle güvenebilirsiniz listsüremax jenerik yineleyici protokolü geçmesi gerekecektir.

Bu, her bir öğenin getirildiği her öğenin getirmesinden l.sortdaha hızlı olmasını sağlar max.

Bunun yerine kullanırsanız sorted(a)sonucu daha yavaş alacağınızı varsayıyorum max(a).


5
Bu varsayım, daha somut hale gelmek için yalnızca tek bir zamanlama uzaklığıdır. Bilginizi sorgulamak değil, sadece böyle bir ekleme, bilmeyenlerin gösterilmesi için önemsizdir.
Reti43

Haklısın, sorted(a)bundan daha yavaş max(a). Şaşırtıcı olmayan bir şekilde, ile aynı hızda a.sort(), ancak neden olmadığına dair varsayımınız - bunun nedeni, OP'nin kabul edilen cevapta belirtildiği gibi testlerinde bir hata yapmasıdır.
martineau

Mesele şu ki, genel yineleme protokolünün log(n)karmaşıklıktaki faktörü dengelemek için yeterli ek yüke sahip olma olasılığı var . Yani bir O(n)algoritmanın, O(nlogn)yeterince büyük bir algoritmadan daha hızlı olduğu garanti edilir n(örneğin, her işlemin süresi algoritmalar arasında farklılık gösterebilir - nlognhızlı adımlar nyavaş adımlardan daha hızlı olabilir ). Bu durumda tam olarak kırılma bile dikkate alınmaz (ancak log nfaktörün küçücük için çok büyük bir faktör olmadığının bilinmesi gerekir n).
skyking
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.