Jon teoriyi zaten ele aldıktan sonra , işte bir uygulama:
function shuffle(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
Algoritma, O(n)
sıralama ise olmalıdır O(n log n)
. Yerel sort()
işleve kıyasla JS kodunu yürütmenin ek yüküne bağlı olarak , bu , dizi boyutlarıyla artması gereken performansta gözle görülür bir farka yol açabilir .
Bobobobo'nun cevabına yapılan yorumlarda , söz konusu algoritmanın eşit dağıtılmış olasılıklar üretmeyebileceğini (uygulamasına bağlı olarak sort()
) belirttim.
Benim argümanım şu satırlarda devam ediyor: Bir sıralama algoritması belirli sayıda c
karşılaştırma gerektirir , örneğin c = n(n-1)/2
Bubblesort için. Rastgele karşılaştırma fonksiyonumuz, her bir karşılaştırmanın sonucunu eşit derecede olası kılar, yani 2^c
eşit derecede olası sonuçlar vardır. Şimdi, her sonucun n!
dizi girdilerinin permütasyonlarından birine karşılık gelmesi gerekir , bu da genel durumda eşit dağılımı imkansız kılar. (Bu bir basitleştirmedir, çünkü gereken gerçek karşılaştırma sayısı giriş dizisine bağlıdır, ancak iddia yine de geçerli olmalıdır.)
Jon'un belirttiği gibi, bu tek başına Fisher-Yates'i kullanmak yerine tercih etmek için bir neden değildir sort()
, çünkü rasgele sayı üreteci n!
permütasyonlara sonlu sayıda sözde rasgele değeri de eşleyecektir. Ancak Fisher-Yates'in sonuçları yine de daha iyi olacaktır:
Math.random()
aralıkta sözde rasgele bir sayı üretir [0;1[
. JS çift duyarlıklı kayan nokta değerleri kullandığından, bu 2^x
olası değerlere karşılık gelir 52 ≤ x ≤ 63
(gerçek sayıyı bulmak için çok tembelim). Kullanılarak oluşturulan bir olasılık dağılımı Math.random()
, atomik olayların sayısı aynı büyüklük sırasındaysa iyi davranmayı durduracaktır.
Fisher-Yates kullanırken, ilgili parametre, 2^52
pratik sınırlamalar nedeniyle asla yaklaşmaması gereken dizinin boyutudur .
Rastgele bir karşılaştırma işleviyle sıralama yaparken, işlev temelde yalnızca dönüş değerinin pozitif mi yoksa negatif mi olduğunu dikkate alır, bu nedenle bu asla bir sorun olmayacaktır. Ancak benzer bir tane var: Karşılaştırma işlevi iyi davrandığından, 2^c
olası sonuçlar, belirtildiği gibi eşit derecede olasıdır. Eğer c ~ n log n
o zaman 2^c ~ n^(a·n)
nerede ise a = const
, bu en azından mümkün kılar, bu 2^c
aynı büyüklüktedir (veya daha azdır) n!
ve böylece eşit olmayan bir dağılıma yol açar, sıralama algoritması permütasyonların nerede eşit olarak eşleneceği olsa bile. Bunun pratik bir etkisi varsa beni aşıyor.
Gerçek sorun, sıralama algoritmalarının permütasyonlarla eşit şekilde eşlenmesinin garanti edilmemesidir. Mergesort'un simetrik olduğunu görmek kolaydır, ancak Bubblesort veya daha da önemlisi Quicksort veya Heapsort gibi bir şey hakkında mantık yürütmek öyle değildir.
Sonuç olarak: sort()
Mergesort kullanıldığı sürece, köşe vakaları dışında makul derecede güvende olmalısınız (en azından 2^c ≤ n!
bunun bir köşe vakası olduğunu umuyorum ), değilse, tüm bahisler kapalıdır.