Метод генерации случайной перестановки, алгоритм Фишера-Йетса — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м (отформатировал псевдокод)
м (Обоснование)
Строка 15: Строка 15:
  
 
==Обоснование==
 
==Обоснование==
Проведем доказательство по индукции. Всего перестановок <tex> n! </tex>, поэтому вероятность каждой из них должна быть равна <tex> \frac {1}{n!}</tex>. Показажем, что на каждом i-ом шаге цикла любая перестановка из первых <tex>i</tex> элементов равновероятна.
+
Проведем доказательство по индукции. Всего перестановок <tex> n! </tex>, поэтому вероятность каждой из них должна быть равна <tex> \frac {1}{n!}</tex>. Показажем, что на каждом <tex>i</tex>-ом шаге цикла любая перестановка из первых <tex>i</tex> элементов равновероятна.
 
* при <tex> i = 1 </tex> перестановка всего одна, и, очевидно, что база верна
 
* при <tex> i = 1 </tex> перестановка всего одна, и, очевидно, что база верна
 
* пусть при <tex> i = k - 1 </tex> каждая перестановка первых <tex>i</tex> элементов равновероятна, то есть вероятность каждой отдельно взятой перестановки  на <tex>i</tex>-ом шаге цикла равна <tex> \frac {1}{(k-1)!}</tex>
 
* пусть при <tex> i = k - 1 </tex> каждая перестановка первых <tex>i</tex> элементов равновероятна, то есть вероятность каждой отдельно взятой перестановки  на <tex>i</tex>-ом шаге цикла равна <tex> \frac {1}{(k-1)!}</tex>
 
: при <tex> i = k </tex>:
 
: при <tex> i = k </tex>:
: <tex> a:array[ a_{1}, a_{2}, ..., a_{k-1}, k, ... ] </tex>
+
: <tex> a = \{ a_{1}, a_{2}, ..., a_{k-1}, k, ... \} </tex>
 
: после <tex>swap(i, random(1..i))</tex> вероятность какого-то числа оказаться на <tex>k</tex>-ом месте равна <tex>\frac{1}{k}</tex>. Вероятность же какой-то перестановки первых <tex>(k-1)</tex> элементов при известном <tex>a_{k}</tex> останется <tex> \frac {1}{(k-1)!}</tex>, что в результате дает, что вероятность перестановки первых <tex>k</tex> элементов равна <tex> \frac {1}{k!}</tex>
 
: после <tex>swap(i, random(1..i))</tex> вероятность какого-то числа оказаться на <tex>k</tex>-ом месте равна <tex>\frac{1}{k}</tex>. Вероятность же какой-то перестановки первых <tex>(k-1)</tex> элементов при известном <tex>a_{k}</tex> останется <tex> \frac {1}{(k-1)!}</tex>, что в результате дает, что вероятность перестановки первых <tex>k</tex> элементов равна <tex> \frac {1}{k!}</tex>
 
<br/>
 
<br/>

Версия 15:01, 22 января 2016

Тасование Фишера–Йетса (названо в честь Рональда Фишера (Ronald Fisher) и Франка Йетса (Frank Yates)) – алгоритм создания случайных перестановок конечного множества, попросту говоря, для случайного тасования множества. Основная процедура тасования Фишера–Йетса аналогична случайному вытаскиванию записок с числами из шляпы или карт из колоды, один элемент за другим, пока элементы не кончатся. Алгоритм обеспечивает эффективный и строгий метод таких операций, гарантирующий несмещённый результат.

Постановка задачи

Необходимо сгенерировать случайную перестановку из [math] n [/math] чисел с равномерным распределением вероятности, если есть в наличии функция для генерации случайного числа в заданном интервале.

Решение

Пусть

  • [math]\mathtt{random(1..i) }[/math] генерирует случайное число в интервале [math] [1;\; i] [/math]

Следующий алгоритм решает задачу:

 int *a randomPermutation(int *a) // *a - указатель на массив типа int длины n
   for i = 1 to n
     j = random(1..i)
     swap(a[i], a[j])
 return a

Обоснование

Проведем доказательство по индукции. Всего перестановок [math] n! [/math], поэтому вероятность каждой из них должна быть равна [math] \frac {1}{n!}[/math]. Показажем, что на каждом [math]i[/math]-ом шаге цикла любая перестановка из первых [math]i[/math] элементов равновероятна.

  • при [math] i = 1 [/math] перестановка всего одна, и, очевидно, что база верна
  • пусть при [math] i = k - 1 [/math] каждая перестановка первых [math]i[/math] элементов равновероятна, то есть вероятность каждой отдельно взятой перестановки на [math]i[/math]-ом шаге цикла равна [math] \frac {1}{(k-1)!}[/math]
при [math] i = k [/math]:
[math] a = \{ a_{1}, a_{2}, ..., a_{k-1}, k, ... \} [/math]
после [math]swap(i, random(1..i))[/math] вероятность какого-то числа оказаться на [math]k[/math]-ом месте равна [math]\frac{1}{k}[/math]. Вероятность же какой-то перестановки первых [math](k-1)[/math] элементов при известном [math]a_{k}[/math] останется [math] \frac {1}{(k-1)!}[/math], что в результате дает, что вероятность перестановки первых [math]k[/math] элементов равна [math] \frac {1}{k!}[/math]


Другой способ обоснования заключается в том, что каждая перестановка в результате работы этого алгоритма может получиться ровно одним способом, причем всегда ровно за [math] n [/math] шагов, таким образом автоматически получается, что все [math] n![/math] перестановок равновероятны.

Неправильные способы реализации

Небольшая модификация этого алгоритма, может резко сказаться на его корректности. Например, следующие два алгоритма работают неправильно:

 for i = 1..n
   swap(i, random(1..n))
 for i = 1..n
   swap(random(1..n), random(1..n))

В самом деле: число способов сгенерировать последовательность в первом случае равно [math]n^n[/math], во втором равно [math] (n^2)^n[/math], а всего последовательностей [math] n![/math]. Для того, чтобы сгенерированные последовательности были равновероятны, необходимо хотя бы, чтобы число способов получить последовательность было кратно их общему числу. То есть в первом случае необходимо [math](n^n) \vdots n![/math] а во втором случае [math]((n^2)^n) \vdots n![/math], что заведомо не выполняется при подстановке любого нечетного числа, начиная с 3.

Примечание

  • Впервые этот алгоритм опубликовали Р.А.Фишер и Ф.Йетс (R.A.Fisher and F. Yates, Statistical Tables (London 1938), Example 12).
  • Нетрудно увидеть, что сложность алгоритма [math] O(n)[/math]

Источники

См.также