Метод генерации случайной перестановки, алгоритм Фишера-Йетса — различия между версиями
Строка 17: | Строка 17: | ||
: при <tex> i = k </tex>: | : при <tex> i = k </tex>: | ||
: <tex> a[\;] = \langle a_{1}, a_{2}, ..., a_{k-1}, k, ... \rangle </tex> | : <tex> a[\;] = \langle a_{1}, a_{2}, ..., a_{k-1}, k, ... \rangle </tex> | ||
− | : после swap(i, random(1..i)) вероятность какого-то числа оказаться на k-ом месте равна <tex>\frac{1}{k}</tex. Вероятность же какой-то перестановки первых (k-1) элементов при известном <tex>a_{k}</tex> останется <tex> \frac {1}{(k-1)!}</tex>, что в результате дает, что вероятность перестановки первых k элементов равна <tex> \frac {1}{k!}</tex> | + | : после swap(i, random(1..i)) вероятность какого-то числа оказаться на k-ом месте равна <tex>\frac{1}{k}</tex>. Вероятность же какой-то перестановки первых (k-1) элементов при известном <tex>a_{k}</tex> останется <tex> \frac {1}{(k-1)!}</tex>, что в результате дает, что вероятность перестановки первых k элементов равна <tex> \frac {1}{k!}</tex> |
<br/> | <br/> | ||
Другой способ обоснования заключается в том, что каждая перестановка в результате работы этого алгоритма может получиться ровно одним способом, причем всегда ровно за <tex> n </tex> шагов, таким образом автоматически получается, что все <tex> n!</tex> перестановок равновероятны.<br/> | Другой способ обоснования заключается в том, что каждая перестановка в результате работы этого алгоритма может получиться ровно одним способом, причем всегда ровно за <tex> n </tex> шагов, таким образом автоматически получается, что все <tex> n!</tex> перестановок равновероятны.<br/> |
Версия 23:07, 15 января 2011
Содержание
Постановка задачи
Необходимо сгенерировать случайную перестановку из
чисел с равномерным распределением вероятности, если есть в наличии функция для генерации случайного числа в заданном интервале.Решение
Пусть
- random(1..i); генерирует случайное число в интервале
- swap(i, j); меняет местами числа на местах i и j в массиве
- и пусть для определенности массив задан:
Следующий алгоритм решает задачу:
for i = 1..n swap(i, random(1..i))
Этот алгоритм носит имя Фишера-Йетса.
Обоснование
Проведем доказательство по индукции. Требуется доказать, что на каждом шаге цикла любая перестановка из первых
элементов равновероятна.- при перестановка всего одна, и, очевидно, что база верна
- пусть при каждая перестановка первых i элементов равновероятна, то есть вероятность каждой отдельно взятой перестановки на i-ом шаге цикла равна
- при :
- после swap(i, random(1..i)) вероятность какого-то числа оказаться на k-ом месте равна . Вероятность же какой-то перестановки первых (k-1) элементов при известном останется , что в результате дает, что вероятность перестановки первых k элементов равна
Другой способ обоснования заключается в том, что каждая перестановка в результате работы этого алгоритма может получиться ровно одним способом, причем всегда ровно за шагов, таким образом автоматически получается, что все перестановок равновероятны.
Неправильные способы реализации
Небольшая модификация этого алгоритма, может резко сказаться на его корректности. Например, следующие два алгоритма работают неправильно:
for i = 1..n swap(i, random(1..n))
for i = 1..n swap(random(1..n), random(1..n))
В самом деле: в первом случае число способов сгенерировать последовательность в первом случае равно
, во втором равно , а всего последовательностей . Для того, чтобы сгенерированные последовательности были равновероятны, необходимо хотя бы, чтобы число способов получить последовательность было кратно их общему числу. То есть в первом случае необходимо а во втором случае , что заведомо не выполняется при подстановке любого нечетного числа, начиная с 3.Примечание
- Впервые этот алгоритм опубликовали Р.А.Фишер и Ф.Ятс (R.A.Fisher and F. Yates, Statistical Tables (London 1938), Example 12).
- Нетрудно увидеть, что сложность алгоритма
Литература
- Дональд Кнут Искусство программирования, том 2. Получисленные методы = The Art of Computer Programming, vol.2. Seminumerical Algorithms. — 3-е изд. — М.: «Вильямс», 2007. — С. 832. — ISBN 0-201-89684-2