Починаючи з цієї цитати Скіта:
Мені подобається не такий спосіб перемішування, в основному на тій підставі, що це O (n log n) без поважних причин, коли легко здійснити O (n) переміщення. Код у питанні "працює", в основному даючи випадковий ( сподіваюсь, унікальний! ) Номер кожному елементу, а потім упорядковує елементи відповідно до цього числа.
Я продовжу трохи пояснюю причину, надіюсь, унікальної!
Тепер, від Inumerable.OrderBy :
Цей метод виконує стабільний сорт; тобто, якщо ключі двох елементів рівні, порядок елементів зберігається
Це дуже важливо! Що станеться, якщо два елементи "отримують" однакове випадкове число? Буває, що вони залишаються в тому ж порядку, в якому вони є в масиві. Тепер, яка можливість цього статися? Важко точно обчислити, але є проблема Дня народження, яка саме ця проблема.
Тепер це реально? Це правда?
Як завжди, коли сумніваєтесь, напишіть кілька рядків програми: http://pastebin.com/5CDnUxPG
Цей невеликий блок коду перетасовує масив з 3-х елементів певну кількість разів, використовуючи алгоритм Fisher-Yates, зроблений назад, алгоритм Fisher-Yates зроблений вперед (на сторінці вікі є два алгоритми псевдо-коду ... Вони виробляють еквівалент результати, але один робиться від першого до останнього елемента, а інший - від останнього до першого елемента), наївний неправильний алгоритм 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 (числових значень)), так що якщо максимальне значення дорівнює 2 ^ 31, я скажу, що ви повинні мати можливість сортувати масиви до 2 ^ 12/2 ^ 13 біт (4096-8192 елементів)