Fisher-Yatesův algoritmus (pojmenovaný po Ronaldu Fisherovi a Fanku Yatesovi) slouží k náhodnému promíchání vstupního seznamu. Všechny algoritmem generované permutace se vyskytují se stejnou pravděpodobností.
Původní algoritmus
Původní verze Fisher-Yatesova algoritmu z roku 1938 byla založena na postupném výběru a vyškrtávání prvků z původního seznamu a zápisu vybraných hodnot do seznamu nového (algoritmus vykonával člověk za použití tužky a papíru).
Popis
V každém svém kroku uživatel náhodně zvolí celé číslo n na intervalu , kde
je počet dosud nevyškrtnutých prvků z prvního seznamu. Poté vždy vyškrtne z tohoto seznamu n-tý dosud nevyškrtnutý prvek a zapíše jej na konec druhého seznamu. Takto postupuje tak dlouho, dokud první seznam obsahuje nevyškrtnuté prvky.
Novodobý algoritmus
Původní procedura je sice šikovná pro ruční zpracování, ale z výpočetního hlediska je nevhodná, jelikož má kvadratickou asymptotickou složitost . Z tohoto důvodu se obvykle v programech používá modifikovaná in-place verze algoritmu s lineární asymptotickou složitostí
.
Popis
Základní myšlenka moderního algoritmu je totožná – náhodný výběr. Procedura v každém svém kroku zvolí číslo n na interavalu , kde k je počet již prohozených čísel (počet již uskutečněných iterací algoritmu) a m je délka vstupního seznamu. Prvek na indexu n (indexováno od 1) poté prohodí s prvkem na indexu m-k. Algoritmus po zamíchání všech prvků, tj. n-1 iteracích, terminuje.
Lepší asymptotické chování této verze plyne z toho, že jsou již permutované hodnoty zapisovány na konec seznamu a k dosud neprohozeným prvkům lze tedy přistupovat s konstantní časovou složitostí (původní algoritmus vyžadoval iteraci kvůli již zpracovaným hodnotám).
Vizualizace
Kód
01.
/**
02.
* Moderni verze Fisher-Yatesova algoritmu
03.
* @param array pole indexovane od 0
04.
*/
05.
function
fisherYates(
array
)
06.
for
i in <
array
.length - 1, 1>
do
07.
index = náhodné číslo z intervalu <0, i)
08.
prohoď(
array
[i],
array
[index])
09.
01.
/**
02.
* An improved version (Durstenfeld) of the Fisher-Yates algorithm with O(n) time complexity
03.
* Permutes the given array
04.
* @param array array to be shuffled
05.
*/
06.
public
static
void
fisherYates(
int
[] array) {
07.
Random r =
new
Random();
08.
for
(
int
i = array.length -
1
; i >
0
; i--) {
09.
int
index = r.nextInt(i);
10.
//swap
11.
int
tmp = array[index];
12.
array[index] = array[i];
13.
array[i] = tmp;
14.
}
15.
}
01.
/**
02.
* An improved version (Durstenfeld) of the Fisher-Yates algorithm with O(n) time complexity
03.
* Permutes the given array
04.
* @param array array to be shuffled
05.
*/
06.
static
void
FisherYates(
int
[] array)
07.
{
08.
Random r =
new
Random();
09.
for
(
int
i = array.Length - 1; i > 0; i--)
10.
{
11.
int
index = r.Next(i);
12.
//swap
13.
int
tmp = array[index];
14.
array[index] = array[i];
15.
array[i] = tmp;
16.
}
17.
}
01.
/**
02.
* An improved version (Durstenfeld) of the Fisher-Yates algorithm with O(n) time complexity
03.
* Permutes the given array
04.
* @param array array to be shuffled
05.
*/
06.
function
fisherYates(array) {
07.
for
(
var
i = array.length - 1; i > 0; i--) {
08.
var
index = Math.floor(Math.random() * i);
09.
//swap
10.
var
tmp = array[index];
11.
array[index] = array[i];
12.
array[i] = tmp;
13.
}
14.
}