Siete alla ricerca di un derangement delle voci.
Prima di tutto, l'algoritmo funziona nel senso che emette un errore casuale, ovvero una permutazione senza punto fisso. Tuttavia ha un enorme difetto (che non ti dispiacerebbe, ma vale la pena tenere a mente): alcuni disallineamenti non possono essere ottenuti con il tuo algoritmo. In altre parole, dà una probabilità pari a zero di alcuni possibili sconvolgimenti, quindi la distribuzione risultante non è sicuramente uniformemente casuale.
Una possibile soluzione, come suggerito nei commenti, sarebbe quella di utilizzare un algoritmo di rifiuto:
- raccogliere una permutazione uniformemente a caso
- se Hax senza punti fissi, restituirlo
- altrimenti riprova
In modo asintotico, la probabilità di ottenere uno squilibrio è vicino a 1/e
= 0,3679 (come si vede nell'articolo di Wikipedia). Ciò significa che per ottenere un disallineamento è necessario generare una media di e
= 2.718 permutazioni, che è piuttosto costoso.
Un modo migliore per farlo sarebbe quello di rifiutare ad ogni passo dell'algoritmo. In pseudocodice, qualcosa di simile (supponendo che l'array originale contiene i
alla posizione i
, cioè a[i]==i
):
for (i = 1 to n-1) {
do {
j = rand(i, n) // random integer from i to n inclusive
} while a[j] != i // rejection part
swap a[i] a[j]
}
La differenza principale dal vostro algoritmo è che ci permettono j
di essere pari a i
, ma solo se lo fa non produrre un punto fisso. È leggermente più lungo da eseguire (a causa della parte di rifiuto) e richiede di essere in grado di verificare se una voce si trova nella sua posizione originale o meno, ma ha il vantaggio di poter produrre ogni possibile squilibrio (uniformemente, per quello importa).
Immagino che gli algoritmi di non rifiuto dovrebbero esistere, ma credo che siano meno diretti.
Edit:
mio algoritmo è in realtà male: si ha ancora una possibilità di finire con l'ultimo punto unshuffled, e la distribuzione non è casuale a tutti, vedere le distribuzioni marginali di una simulazione: 
Un algoritmo che produce diramazioni distribuite uniformemente può essere trovato here, con qualche contesto sul problema, spiegazioni approfondite e analisi.
Secondo Edit:
In realtà l'algoritmo è noto come Sattolo's algorithm, ed è noto per la produzione di tutti i cicli con uguale probabilità. Quindi qualsiasi derangement che non sia un ciclo ma un prodotto di diversi cicli disgiunti non può essere ottenuto con l'algoritmo. Per esempio, con quattro elementi, la permutazione che scambia 1 e 2, e 3 e 4 è un disordine ma non un ciclo.
Se non ti dispiace ottenere solo cicli, l'algoritmo di Sattolo è la strada da seguire, è in realtà molto più veloce di qualsiasi algoritmo di derangement uniforme, poiché non è necessario alcun rifiuto.
Inserire in modo casuale ciascun elemento in un'altra posizione. C'è una piccola possibilità che non riesci a trovare una posizione per l'ultimo ma poi ricominciare da capo. – adrianm
https://en.wikipedia.org/wiki/_algorithm di Sattolo – Bergi
Una ricorrenza finita proverebbe matematicamente che il tuo algoritmo funziona: alla fine dell'iterazione i, l'elemento in posizione i non è più l'elemento originale. Quando in iterazione n-2, i dati [n-2] vengono automaticamente mescolati con i dati [n-1]. Pertanto, se i dati [n-1] mantengono ancora il valore originale, vengono scambiati all'ultima iterazione. Lo stesso vale per i dati [n-1]. – Rerito