Böl ve Yönet algoritmaları - Neden ikiden daha fazla bölüme ayrılmıyorsunuz?


33

Bu tür hızlı sıralama ve MergeSort olarak bölmek ve fethetmek algoritmaları, giriş bölme (giriş metinlerde az) genellikle iki , ve iki küçük veri daha sonra, ardışık ele alınmaktadır. İki yarının tüm veri setiyle uğraşma işinin yarısından daha azını alırsa, bunun bir sorunu çözmenin daha hızlı olacağını bana mantıklı geliyor. Peki neden veriyi üç bölüme ayırmıyorsunuz? Dört? n ?

Verileri birçok alt kümeye bölme çalışmasının buna değmeyeceğini tahmin ediyorum, ancak birinin iki alt kümede durması gerektiğine dair sezgimden yoksunum.

Ayrıca 3 yollu quicksort'a birçok referans gördüm. Bu ne zaman daha hızlı? Uygulamada ne kullanılır?


Bir diziyi üç parçaya bölen quicksort'a benzer bir algoritma oluşturmayı deneyin.
gnasher729

Yanıtlar:


49

İki yarının tüm veri setiyle uğraşma işinin yarısından daha azını alırsa, bunun bir sorunu çözmeyi daha hızlı hale getirmesi bana mantıklı geliyor.

Bu, böl ve fethe algoritmalarının özü değildir . Genellikle mesele, algoritmaların “tüm veri setiyle tümüyle” başa çıkamadığıdır. Bunun yerine, çözülmesi önemsiz parçalara bölünür (iki sayıyı sıralamak gibi), sonra bunlar önemsizce çözülür ve sonuçlar tam veri seti için bir çözüm getirecek şekilde yeniden birleştirilir.

Peki neden veriyi üç bölüme ayırmıyorsunuz? Dört? n?

Esas olarak, onu ikiden fazla parçaya bölmek ve ikiden fazla sonucu yeniden biraraya getirmek, daha karmaşık bir uygulama ile sonuçlanır ancak algoritmanın temel (Büyük O) özelliğini değiştirmez - fark sabit bir faktördür ve yavaşlamaya neden olabilir 2'den fazla alt grubun bölünmesi ve yeniden birleştirilmesi ek yük oluşturursa.

Örneğin, 3 yollu bir birleştirme sıralaması yaparsanız, yeniden birleştirme aşamasında, artık her öğe için 1 yerine 2 karşılaştırma gerektiren en büyük 3 öğeyi bulmanız gerekir, bu nedenle toplamda iki kat daha fazla karşılaştırma yaparsınız. . Buna karşılık, tekrarlama derinliğini bir ln (2) / ln (3) == 0,63 oranında azaltırsınız, böylece% 37 daha az takas değeriniz vardır, ancak 2 * 0,63 ==% 26 daha fazla karşılaştırma (ve hafıza erişim). Bunun iyi veya kötü olması donanımınızda hangisinin daha pahalı olduğuna bağlıdır.

Ayrıca 3 yollu quicksort'a birçok referans gördüm. Bu ne zaman daha hızlı?

Görünüşe göre, bir quick pivot çift pivot varyantının aynı sayıda karşılaştırmayı gerektirdiği kanıtlanabilir, ancak ortalama olarak% 20 daha az takas, bu nedenle net bir kazanç.

Uygulamada ne kullanılır?

Bugünlerde neredeyse hiç kimse artık kendi sıralama algoritmalarını programlar; Bir kütüphane tarafından sağlanan bir kullanın. Örneğin, Java 7 API'si aslında çift eksenli hızlı bağlantı noktasını kullanır.

Aslında bir nedenden ötürü kendi sıralama algoritmasını programlayan insanlar, basit 2-yollu varyantlara bağlı kalma eğilimindedir, çünkü hatalar için daha az potansiyel çoğu zaman% 20 daha iyi performans gösterir. Unutmayın: Bugüne kadarki en önemli performans iyileştirme, kodun “çalışmamadan” “çalışmaya” gitmesidir.


1
Küçük not: Java 7, Dual-Pivot hızlı erişim noktalarını yalnızca ilkelleri sıralarken kullanır . Nesneleri sıralamak için Timsort kullanır.
Bakuriu

1
"Bugünlerde neredeyse hiç kimse artık kendi sıralama algoritmalarını programlamıyor" ve (daha da önemlisi) "Unutma: şu ana kadarki en önemli performans iyileştirme, kodun" çalışmama "den" çalışma "ya geçmesidir. Ancak, örneğin bir veri setini birçok parçaya bölerse, bu ek yükün hala önemsiz olup olmadığını bilmek isterim. Olduğu gibi, başka insanlar da var: bealto.com/gpu-sorting_intro.html stackoverflow.com/questions/1415679/… devgurus.amd.com/thread/157159
AndrewJacksonZA

Biraz yavaşım. Neden 2 * 0.69 daha fazla kıyaslama yapıldığını açıklayabilir mi? 0.69'un nereden geldiğinden emin değilim.
jeebface

@ jeebface ayy, bu bir yazım hatası oldu (şimdi düzeltildi). 0,63 (özyineleme derinliğinde azalma), sonra% 26 daha fazla sonuç da işe yarıyor.
Michael Borgwardt

30

Asimptotik olarak konuşursak, önemli değil. Örneğin, ikili arama yaklaşık olarak log 2  n karşılaştırma yapar ve üçlü arama yaklaşık olarak log 3  n karşılaştırma yapar . Logaritmalarını biliyorsanız, o günlüğü bilirsiniz a  x = log b  x / log b  a ' , bu nedenle ikili arama sadece yaklaşık 1 / log 3 yapar 2 - Üçlü arama kadar çok kıyaslama 1,5 kez. Bu aynı zamanda hiç kimsenin logaritmanın tabanını büyük Oh olarak göstermemesinin sebebidir: Tabii, gerçek olan ne olursa olsun, her zaman logaritmadan belirli bir tabandaki sabit bir faktördür. Bu yüzden problemi daha fazla alt gruba bölmek zaman karmaşıklığını arttırmaz ve pratik olarak daha karmaşık mantığa ağır basmak için yeterli değildir. Aslında, bu karmaşıklık pratik performansı olumsuz etkileyebilir, önbellek basıncını arttırır veya mikro optimizasyonları daha az olanaksız kılar.

Öte yandan, bazı ağaç-veri veri yapıları, genellikle başka nedenlerle olsa da, yüksek bir dallanma faktörü kullanır (3'ten çok, genellikle 32 veya daha fazla). Bellek hiyerarşisinin kullanımını geliştirir: RAM'de depolanan veri yapıları önbelleği daha iyi kullanır, diskte depolanan veri yapıları daha az HDD-> RAM okur.


Evet, octree'yi ikili ağaç yapısından daha fazlasının özel bir uygulaması için araştırın.
daaxix

@daaxix btree muhtemelen daha yaygındır.
Jules

4

İkie değil N'ye bölen arama / sıralama algoritmaları var.

Basit bir örnek, O (1) zaman alan karma kodlamaya göre aramadır.

Karma işlevi siparişi koruyorsa, O (N) sıralama algoritması yapmak için kullanılabilir. (Herhangi bir sıralama algoritmasını, sonuçta bir sayının nereye basması gerektiğini N arama yapmak gibi düşünebilirsiniz.)

Temel sorun, bir program bazı verileri incelediğinde ve ardından aşağıdaki durumlara girdiğinde, aşağıdaki takip eden durumların sayısı ve olasılıklarının ne kadar yakınına sahip olmalarıdır?

Bir bilgisayar iki sayının bir karşılaştırmasını yaptığında, örneğin her iki yolun da eşit olması muhtemel ise, ya atlar ya da atlarsa, program sayacı "her yol hakkında bir bit bilgi içerir", yani ortalama olarak bir "öğrendi" bit. Eğer bir problem M bitlerinin öğrenilmesini gerektiriyorsa, o zaman ikili kararlar kullanarak, M kararlarından daha az cevap veremez. Bu nedenle, örneğin, 1024 boyutunda sıralanmış bir tabloda bir sayı aramak, yalnızca daha azının yeterli sonuçlara sahip olmaması nedeniyle, ancak kesinlikle bundan daha fazlasını yapabileceği durumlarda, 10 ikili karardan daha azıyla yapılamaz.

Bir bilgisayar bir sayı aldığında ve onu bir dizine dönüştürdüğünde, dizideki element sayısının 2 log tabanını "öğrenir" ve sabit zamanda yapar. Örneğin, 1024 girişli bir atlama tablosu varsa, hepsi eşit ya da daha az muhtemeldir, o zaman o masadan atlamak 10 bit "öğrenir". Karma kodlamanın arkasındaki temel numara budur. Buna bir sıralama örneği bir iskambil destesini nasıl sıralayabileceğinizdir. Her kart için bir tane olmak üzere 52 kutu var. Her kartı yerine oturtun ve hepsini toplayın. Alt bölüm gerekmez.


1

Bu, genel bölünme ve fethetme ile ilgili bir soru olduğu için, sadece sıralama değil, Master Teoremini kimsenin getirmemiş olmasına şaşırdım.

Kısacası, bölme ve fethetme algoritmalarının çalışma süresi iki karşı güç tarafından belirlenir: daha büyük problemleri küçük problemlere dönüştürmekten aldığınız fayda ve daha fazla problem çözmek için ödediğiniz fiyat. Algoritmanın detaylarına bağlı olarak, bir problemi ikiden fazla parçaya bölmek ödeyebilir veya ödemeyebilir. Her adımda aynı sayıda alt probleme bölünürseniz ve sonuçları her adımda birleştirmenin zaman karmaşıklığını bilirseniz, Master Teoremi size genel algoritmanın zaman karmaşıklığını söyleyecektir.

Karatsuba çoğalması için algoritma basamak sayısını sıradan çarpma algoritması (n ^ 2) O yendi (n, O bir işletim süresinin (3, n ^ log_2 3) elde etmek için, 3-yollu bölme ve işgal etmek kullanır sayılar).


Master teoreminde, yarattığınız alt problemlerin sayısı tek faktör değildir. Karatsuba ve kuzeni Strassen'de bu gelişme aslında bazı alt sorunların akıllıca birleştirilmesi çözümlerinden kaynaklanıyor, bu nedenle alt sorunlara özyinelemeli çağrıların sayısını azaltırsınız. Kısacası, byüksek lisans teorisinin yükselmesi a, ilerideki bölümlerde bir iyileşme elde etmeniz için yavaşlamayı gerektirir .
Bilgilendirilmiş

-4

İkili doğası gereği, bir bilgisayarı 2'ye bölmek için çok verimlidir ve 3'te o kadar fazla olmaz. İlk önce 2'ye bölerek 3'e bölünür ve sonra parçalardan birini tekrar 2'ye bölersiniz. 3 bölümünüzü almak için 2 ile 2'ye bölebilirsiniz.

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.