Начиная с этой цитаты Скита:
Мне не нравится способ тасования, в основном на том основании, что это O (n log n) без веской причины, когда легко реализовать O (n) тасование. Код в вопросе «работает», в основном давая случайное ( мы надеемся, уникальное! ) Число каждому элементу, затем упорядочивая элементы в соответствии с этим числом.
Я продолжу немного объяснять причину уникальной надежды!
Теперь из Enumerable.OrderBy :
Этот метод выполняет стабильную сортировку; то есть, если ключи двух элементов равны, порядок элементов сохраняется
Это очень важно! Что произойдет, если два элемента «получат» одно и то же случайное число? Бывает, что они остаются в том же порядке, что и в массиве. Теперь, какова вероятность того, что это произойдет? Трудно точно рассчитать, но есть проблема дня рождения, которая именно эта проблема.
Теперь это реально? Это правда?
Как всегда, если сомневаетесь, напишите несколько строчек программы: http://pastebin.com/5CDnUxPG
Этот небольшой блок кода перемешивает массив из 3 элементов определенное количество раз, используя алгоритм Фишера-Йейтса, выполненный в обратном направлении, алгоритм Фишера-Йейтса, выполненный в прямом направлении (на вики- странице есть два алгоритма псевдокода ... Они производят эквивалентные результаты, но один выполняется от первого до последнего элемента, а другой выполняется от последнего до первого элемента), наивный неправильный алгоритм http://blog.codinghorror.com/the-danger-of-naivete/ и используя .OrderBy(x => r.Next())
и .OrderBy(x => r.Next(someValue))
.
Теперь Random.Next является
32-разрядное целое число со знаком, большее или равное 0 и меньшее, чем MaxValue.
так что это эквивалентно
OrderBy(x => r.Next(int.MaxValue))
Чтобы проверить, существует ли эта проблема, мы могли бы увеличить массив (что-то очень медленное) или просто уменьшить максимальное значение генератора случайных чисел ( int.MaxValue
это не «специальное» число ... Это просто очень большое число). В конце концов, если алгоритм не смещен из-за стабильности OrderBy
, любой диапазон значений должен давать тот же результат.
Затем программа проверяет некоторые значения в диапазоне 1 ... 4096. Глядя на результат, совершенно ясно, что для низких значений (<128) алгоритм очень смещен (4-8%). С 3 значениями вам нужно как минимум r.Next(1024)
. Если вы сделаете массив больше (4 или 5), то даже этого r.Next(1024)
будет недостаточно. Я не специалист по тасованию и математике, но я думаю, что для каждого дополнительного бита длины массива вам нужно 2 дополнительных бита максимального значения (потому что парадокс дня рождения связан с sqrt (numvalues)), поэтому что если максимальное значение равно 2 ^ 31, я скажу, что вы должны иметь возможность сортировать массивы до 2 ^ 12/2 ^ 13 бит (4096-8192 элементов)