A partir desta citação de Skeet:
Não é uma maneira de embaralhar que eu gosto, principalmente porque é O (n log n) sem um bom motivo, quando é fácil implementar um embaralhamento de O (n). O código da pergunta "funciona" basicamente atribuindo um número aleatório ( espero que único! ) A cada elemento e, em seguida, ordenando os elementos de acordo com esse número.
Vou explicar um pouco o motivo do que se espera que seja único!
Agora, a partir do Enumerable.OrderBy :
Este método executa uma classificação estável; isto é, se as chaves de dois elementos são iguais, a ordem dos elementos é preservada
Isto é muito importante! O que acontece se dois elementos "recebem" o mesmo número aleatório? Acontece que eles permanecem na mesma ordem em que estão na matriz. Agora, qual é a possibilidade disso acontecer? É difícil calcular exatamente, mas existe o problema do aniversário que é exatamente esse problema.
Agora é real? É verdade?
Como sempre, em caso de dúvida, escreva algumas linhas de programa: http://pastebin.com/5CDnUxPG
Esse pequeno bloco de código embaralha uma matriz de 3 elementos um certo número de vezes, usando o algoritmo Fisher-Yates feito para trás, o algoritmo Fisher-Yates feito para frente (na página da wiki existem dois algoritmos de pseudo-código ... Eles produzem equivalentes resultados, mas um é feito do primeiro ao último elemento, enquanto o outro é feito do último ao primeiro elemento), o ingênuo algoritmo errado de http://blog.codinghorror.com/the-danger-of-naivete/ e usando o .OrderBy(x => r.Next())
e o .OrderBy(x => r.Next(someValue))
.
Agora, Random.Next é
Um inteiro assinado de 32 bits maior ou igual a 0 e menor que MaxValue.
então é equivalente a
OrderBy(x => r.Next(int.MaxValue))
Para testar se esse problema existe, podemos aumentar a matriz (algo muito lento) ou simplesmente reduzir o valor máximo do gerador de números aleatórios ( int.MaxValue
não é um número "especial" ... É simplesmente um número muito grande). No final, se o algoritmo não for influenciado pela estabilidade do OrderBy
, qualquer faixa de valores deverá fornecer o mesmo resultado.
O programa então testa alguns valores, no intervalo de 1 a 4096. Observando o resultado, é bastante claro que, para valores baixos (<128), o algoritmo é muito tendencioso (4-8%). Com 3 valores você precisa pelo menos r.Next(1024)
. Se você aumentar a matriz (4 ou 5), nem isso r.Next(1024)
será suficiente. Eu não sou especialista em baralhar e em matemática, mas acho que para cada bit extra de comprimento da matriz, você precisa de 2 bits extras de valor máximo (porque o paradoxo do aniversário está conectado ao sqrt (numvalues)), então que, se o valor máximo for 2 ^ 31, direi que você poderá classificar matrizes de até 2 ^ 12/2 ^ 13 bits (4096-8192 elementos)