We have
n
≥
1
n≥1
n≥1 distinct objects i.e. an array of length
n
n
n with distinct objects, and we want to shuffle them using an algorithm such that every possible permutation out of a totally of
n
!
n!
n! is equally likely.
The Algorithm
Description
Suppose we are given a random number generator.
Start from the last element of the array, generate a random integer between
0
0
0 and
n
−
1
n-1
n−1 (all inclusive), say
r
1
r_1
r1, and swap the
r
1
r_1
r1th and the
(
n
−
1
)
(n-1)
(n−1)th elements.
Then generate a random integer between
0
0
0 and
n
−
2
n-2
n−2, say
r
2
r_2
r2, then we swap the
r
2
r_2
r2th and the
n
−
2
n-2
n−2th elements.
Continue this process until we get to generate a random integer between
0
0
0 and
1
1
1, say
r
n
−
1
r_{n-1}
rn−1, then we swap
r
n
−
1
r_{n-1}
rn−1st and
1
1
1th elements.
No matter what we generated in the last step, the next step only allows us to generate
0
=
r
n
0=r_n
0=rn as the only possible random integer, so we keep everything unchanged as we are swapping
0
0
0th element and the
0
0
0th element. Thus, this last step is never needed.
One shuffling is completed.
Pseudo Code
Assume arr is an array of length
n
≥
1
n≥1
n≥1. Assuming the array index starts at
0
0
0:
for i = n-1,....,1{ // the i = 0 step is not actually needed
l = randInt 0 <= l <= i
swap(arr[i], arr[l])
}
Proof
Let the index start from
1
1
1 from now on. We want to prove that for any permutation of the
n
n
n objects in the original array, the probability of obtaining it by the algorithm is always
1
n
!
\frac{1}{n!}
n!1.
Observe a fact from the algorithm:
After the first step, whichever object from the original array gets fixed to the last position stay fixed forever because after the first step, the second step will only exchange two terms among the previous
n
−
1
n-1
n−1 terms.
Same for the second step: after the second step, whichever object gets fixed to the next-to-the-last position gets fixed forever and so on.
Thus, a direct result of this observation is that once we choose some permutation of the objects of the original array, we can build this permutation by
n
n
n consecutive steps that needs to be done in such an order that the first step is to decide which term goes to the last position, the second step is to decide which goes to the next to last position and so on, which will, in turn, allows us to use the multiplication principle.
Therefore, assume
a
1
,
.
.
.
,
a
n
a_1,...,a_n
a1,...,an is an arbitrary permutation, with their original indices in the array being
x
1
,
.
.
.
.
,
x
n
x_1,....,x_n
x1,....,xn. We examine all the steps needed to obtain this permutation:
The first step generates a random integer between
1
1
1 and
n
n
n, so if the generator is indeed random, the probability of generating
x
n
x_n
xn from
{
1
,
.
.
.
,
n
}
\{1,...,n\}
{1,...,n} is
1
n
\frac{1}{n}
n1, therefore, the probability that
a
n
a_n
an gets fixed to the last position is
1
n
\frac{1}{n}
n1.
The second step generates a random integer in
S
=
{
1
,
.
.
.
,
n
}
∖
{
x
n
}
S=\{1,...,n\} \setminus \{x_n\}
S={1,...,n}∖{xn}, which are
n
−
1
n-1
n−1 integers, so
P
(
{
P(\{
P({generating
x
n
−
1
∈
S
}
)
=
1
n
−
1
x_{n-1}\in S\})=\frac{1}{n-1}
xn−1∈S})=n−11, which is the probability that
a
n
−
1
a_{n-1}
an−1 gets fixed to the
(
n
−
1
)
(n-1)
(n−1)th position.
Similarly, the probability that
a
n
−
2
a_{n-2}
an−2 gets fixed to the
(
n
−
2
)
(n-2)
(n−2)th position is thus
1
n
−
2
\frac{1}{n-2}
n−21.
This process continues until we have reached the
1
1
1st position, where the only integer that can be generated is
1
1
1, and we only have one index,
x
1
x_1
x1, left (as we have chosen
n
−
1
n-1
n−1 integers already), so the probability that
a
1
a_1
a1 gets fixed to the first position is certainly
1
1
1.
By multiplication principle, since we achieved the permutation
a
1
,
.
.
.
,
a
n
a_1,...,a_n
a1,...,an by these
n
n
n consecutive steps, the probability of getting this permutation is thus
1
n
⋅
1
n
−
1
.
.
.
⋅
1
=
1
n
!
\frac{1}{n}\cdot \frac{1}{n-1} ...\cdot 1=\frac{1}{n!}
n1⋅n−11...⋅1=n!1
Implementation in Java
int n =5;char[] CardValues =newchar[]{'a','b','c','d','e'};for(int i = n-1; i >=0; i--){int r =(int)((i +1)* Math.random());// r in [0,i]char temp = CardValues[i];
CardValues[i]= CardValues[r];
CardValues[r]= temp;}