Метод генерации случайной перестановки, алгоритм Фишера-Йетса — различия между версиями
(→Неправильные способы реализации) |
|||
Строка 22: | Строка 22: | ||
==Неправильные способы реализации== | ==Неправильные способы реализации== | ||
− | Небольшая модификация этого алгоритма, может резко сказаться на его корректности. | + | Небольшая модификация этого алгоритма, может резко сказаться на его корректности. |
+ | |||
+ | Пример неправильной реализации: | ||
'''for''' i = n '''downto''' 1 | '''for''' i = n '''downto''' 1 | ||
swap(i, random(1..n)) | swap(i, random(1..n)) | ||
+ | В данном случае число способов сгенерировать последовательность равно <tex>n^n</tex>, в то время как существует всего <tex> n!</tex> возможных перестановок из <tex> n</tex> элементов. Поскольку <tex> n^n</tex> никогда не может делиться на <tex> n!</tex> без остатка при <tex> n > 2</tex> (так как <tex> n!</tex> делится на число <tex> n - 1</tex> , которое не имеет с <tex> n</tex> общих простых делителей), то некоторые перестановки должны появляться чаще, чем другие. | ||
+ | Другой пример неправильной реализации: | ||
'''for''' i = n '''downto''' 1 | '''for''' i = n '''downto''' 1 | ||
swap(random(1..n), random(1..n)) | swap(random(1..n), random(1..n)) | ||
− | + | Теперь уже число способов сгенерировать последовательность равно <tex>(n^2)^n</tex>. По той же причине, что и раньше <tex> (n^2)^n</tex> не делится на <tex> n!</tex> без остатка при <tex> n > 2</tex> ,следовательно некоторые перестановки будут появляться еще чаще. | |
− | |||
==См.также== | ==См.также== |
Версия 05:12, 23 января 2016
Тасование Фишера – Йетса (названо в честь Рональда Фишера (Ronald Fisher) и Франка Йетса (Frank Yates)) — алгоритм создания случайных перестановок конечного множества, попросту говоря, для случайного тасования множества. Основная процедура тасования Фишера – Йетса аналогична случайному вытаскиванию записок с числами из шляпы или карт из колоды, один элемент за другим, пока элементы не кончатся. Алгоритм обеспечивает эффективный и строгий метод таких операций, гарантирующий несмещённый результат. Время работы алгоритма
Содержание
Применение алгоритма
Задача:
Необходимо сгенерировать случайную перестановку из
чисел с равномерным распределением вероятности, если в наличии есть функция для генерации случайного
числа в заданном интервале.
Решение:
Пусть
Следующий алгоритм решает задачу:
int[] randomPermutation(int[] a) // n — длина перестановки for i = n downto 1 j = random(1..i) swap(a[i], a[j]) return a
Обоснование
Корректность данного алгоритма очевидна. На каждой итерации цикла мы выбираем случайный элемент из всех оставшихся, то есть у нас есть
способов выбрать элемент, способов выбрать элемент ... способ выбрать последний элемент. Таким образом, последовательность длины мы можем получить способами, что совпадает с числом различных перестановок длины . Это означает, что вероятность выбрать любую перестановку длины равна , то есть все перестановки равновероятны.Неправильные способы реализации
Небольшая модификация этого алгоритма, может резко сказаться на его корректности.
Пример неправильной реализации:
for i = n downto 1 swap(i, random(1..n))
В данном случае число способов сгенерировать последовательность равно
, в то время как существует всего возможных перестановок из элементов. Поскольку никогда не может делиться на без остатка при (так как делится на число , которое не имеет с общих простых делителей), то некоторые перестановки должны появляться чаще, чем другие.Другой пример неправильной реализации:
for i = n downto 1 swap(random(1..n), random(1..n))
Теперь уже число способов сгенерировать последовательность равно
. По той же причине, что и раньше не делится на без остатка при ,следовательно некоторые перестановки будут появляться еще чаще.См.также
Источники информации
- Д.Э. Кнут Искусство программирования, том 2. Получисленные методы — 3-е изд. — М.: «Вильямс», 2007. — С. 832. — ISBN 0-201-89684-2
- Википедия - Тасование Фишера–Йетса
- Wikipedia - Fisher-Yates shuffle