2012-01-14 10 views
11

Il classico Fisher Yates simile a questa:Fisher Yates variazione

void shuffle1(std::vector<int>& vec) 
{ 
    int n = vec.size(); 
    for (int i = n - 1; i > 0; --i) 
    { 
     std::swap(vec[i], vec[rand() % (i + 1)]); 
    } 
} 

Ieri, ho implementato l'iterazione "a ritroso" per errore:

void shuffle2(std::vector<int>& vec) 
{ 
    int n = vec.size(); 
    for (int i = 1; i < n; ++i) 
    { 
     std::swap(vec[i], vec[rand() % (i + 1)]); 
    } 
} 

È questa versione in alcun modo peggiore (o migliore) rispetto al primo? Inclina le probabilità risultanti?

+0

Supporre "peggio" significa "produrre una distribuzione non uniforme", giusto? –

+0

@ R.MartinhoFernandes: Giusto. 'È distorta le probabilità risultanti?' – fredoverflow

+0

È più simile a una domanda di matematica. - Come domanda di programmazione, perché stai implementando questa funzione in C++? È nella libreria standard (random_shuffle). – UncleBens

risposta

3

Sì, è pari distribuzione assumendo rand() è. Lo dimostreremo dimostrando che ogni input può generare ogni permutazione con uguale probabilità.

N = 2 può essere facilmente provato. Lo disegneremo come un albero in cui i bambini rappresentano ogni stringa che puoi ottenere inserendo il carattere dopo la virgola nella stringa più a sinistra.

0,1 //input where 0,1 represent indices 
01 10 //output. Represents permutations of 01. It is clear that each one has equal probability 

Per N, avremo ogni permutazioni di N-1, e scambiando a caso l'ultimo carattere per N

(N-1 0th permutation),N  .....   (N-1 Ith permutation),N ________________________ 
    /   \      /     \        \ 
0th permutation of N 1st permutation.... (I*N)th permutation ((I*N)+1)th permutation .... (I*N)+(I-1)th permutation 

Questa induzione di merda dovrebbe portare ad esso che ha una distribuzione uniforme.


Esempio:

N = 2:

0,1 
01 10 // these are the permutations. Each one has equal probability 

N = 3:

  0,1|2   // the | is used to separate characters that we will insert later 
    01,2   10,2 // 01, 10 are permutations from N-1, 2 is the new value 
210 021 012 201 120 102 // these are the permutations, still equal probability 

N = 4: (curvo per facilitare la lettura)

              0,1|23 

                 01,2|3 10,2|3 

              012,3 021,3 210,3 102,3 120,3 201,3 


            1203 1230 1302 3201 
             2103 2130 2301 3102 1023 1032 1320 3021 

ecc

1

Mi sembra OK (assumendo rand()% N è imparziale, che non è). Sembra che sia possibile dimostrare che ogni permutazione di input è prodotta esattamente da 1 sequenza di scelte casuali, in cui ogni scelta casuale è bilanciata.

confronta questo con un'implementazione difettosa, come ad esempio

for (int i = 0; i < v.size(); ++i) { 
    swap(v[i], v[rand() % v.size()]); 
} 

Qui si può vedere che ci sono n n ugualmente probabili modi per produrre n! permutazioni, e dal momento che n n non è equamente divisibile per n! dove n> 2, alcune di queste permutazioni devono essere prodotte più spesso di altre.

Problemi correlati