A partire da questa citazione di Skeet:
Non è un modo di mescolare che mi piace, principalmente per il fatto che è O (n log n) senza una buona ragione quando è facile implementare un O (n) shuffle. Il codice nella domanda "funziona" in sostanza dando un numero casuale (si spera univoco! ) A ciascun elemento, quindi ordinando gli elementi in base a quel numero.
Continuerò un po 'spiegando il motivo per cui si spera sia unico!
Ora, da Enumerable.OrderBy :
Questo metodo esegue un ordinamento stabile; cioè se le chiavi di due elementi sono uguali, l'ordine degli elementi viene preservato
Questo è molto importante! Cosa succede se due elementi "ricevono" lo stesso numero casuale? Accade che rimangano nello stesso ordine in cui si trovano nell'array. Ora, qual è la possibilità che ciò accada? È difficile calcolare esattamente, ma c'è il problema del compleanno che è esattamente questo problema.
Adesso è reale? È vero?
Come sempre, in caso di dubbi, scrivi alcune righe di programma: http://pastebin.com/5CDnUxPG
Questo piccolo blocco di codice mescola un array di 3 elementi un certo numero di volte usando l'algoritmo Fisher-Yates fatto al contrario, l'algoritmo Fisher-Yates fatto in avanti (nella pagina wiki ci sono due algoritmi pseudo-codice ... Producono equivalenti risultati, ma uno viene eseguito dal primo all'ultimo elemento, mentre l'altro viene eseguito dall'ultimo al primo elemento), l'ingenuo algoritmo errato di http://blog.codinghorror.com/the-danger-of-naivete/ e l'utilizzo di .OrderBy(x => r.Next())
e il .OrderBy(x => r.Next(someValue))
.
Ora, Random.Next è
Un numero intero con segno a 32 bit che è maggiore o uguale a 0 e inferiore a MaxValue.
quindi è equivalente a
OrderBy(x => r.Next(int.MaxValue))
Per verificare se questo problema esiste, potremmo allargare l'array (qualcosa di molto lento) o semplicemente ridurre il valore massimo del generatore di numeri casuali ( int.MaxValue
non è un numero "speciale" ... È semplicemente un numero molto grande). Alla fine, se l'algoritmo non è influenzato dalla stabilità di OrderBy
, allora qualsiasi intervallo di valori dovrebbe dare lo stesso risultato.
Il programma quindi verifica alcuni valori, nell'intervallo 1 ... 4096. Guardando il risultato, è abbastanza chiaro che per valori bassi (<128), l'algoritmo è molto distorto (4-8%). Con 3 valori è necessario almeno r.Next(1024)
. Se ingrandisci l'array (4 o 5), r.Next(1024)
non è nemmeno sufficiente. Non sono un esperto di mescolanza e matematica, ma penso che per ogni ulteriore bit di lunghezza dell'array, siano necessari 2 bit extra di valore massimo (perché il paradosso del compleanno è collegato allo sqrt (valori numerici)), quindi che se il valore massimo è 2 ^ 31, dirò che dovresti essere in grado di ordinare le matrici fino a 2 ^ 12/2 ^ 13 bit (4096-8192 elementi)