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