Shuffle an Array in Place
Question: How do you shuffle an array in place?
伪代码如下:
To shuffle an array a of n elements (indices 0..n-1): for i from n − 1 downto 1 do j ← random integer with 0 ≤ j ≤ i exchange a[j] and a[i]
// Shuffle a deck of cards Random random = new Random(); for (int i = cards.size() - 1; i >= 0; i--) { int j = random.nextInt(i + 1); /* swap cards i,j */ Card card = cards.get(i); cards.set(i, cards.get(j)); cards.set(j, card); }
The Fisher–Yates shuffle, as implemented by Durstenfeld, is an in-place shuffle. That is, given a preinitialized array, it shuffles the elements of the array in place, rather than producing a shuffled copy of the array. This can be an advantage if the array to be shuffled is large.
To simultaneously initialize and shuffle an array, a bit more efficiency can be attained by doing an "inside-out" version of the shuffle. In this version, one successively places element number i into a random position among the first i positions in the array, after moving the element previously occupying that position to position i. In case the random position happens to be number i, this "move" (to the same place) involves an uninitialised value, but that does not matter, as the value is then immediately overwritten. No separate initialization is needed, and no exchange is performed. In the common case where source is defined by some simple function, such as the integers from 0 to n − 1, source can simply be replaced with the function sincesource is never altered during execution.
To initialize an array a of n elements to a randomly shuffled copy of source, both 0-based: for i from 0 to n − 1 do j ← random integer with 0 ≤ j ≤ i if j ≠ i a[i] ← a[j]
a[j] ← source[i]
We'll start by writing out the numbers from 1 to 8 as before:
Range Roll Scratch Result
1 2 3 4 5 6 7 8 |
For our first roll, we roll a random number from 1 to 8: this time it's 6, so we swap the 6th and 8th numbers in the list:
Range Roll Scratch Result
1–8 | 6 | 1 2 3 4 5 8 7 | 6 |
The next random number we roll from 1 to 7, and turns out to be 2. Thus, we swap the 2nd and 7th numbers and move on:
Range Roll Scratch Result
1–7 | 2 | 1 7 3 4 5 8 | 2 6 |
The next random number we roll is from 1 to 6, and just happens to be 6, which means we leave the 6th number in the list (which, after the swap above, is now number 8) in place and just move to the next step. Again, we proceed the same way until the permutation is complete:
Range Roll Scratch Result
1–6 | 6 | 1 7 3 4 5 | 8 2 6 |
1–5 | 1 | 5 7 3 4 | 1 8 2 6 |
1–4 | 3 | 5 7 4 | 3 1 8 2 6 |
1–3 | 3 | 5 7 | 4 3 1 8 2 6 |
1–2 | 1 | 7 | 5 4 3 1 8 2 6 |
At this point there's nothing more that can be done, so the resulting permutation is 7 5 4 3 1 8 2 6.
reference:
http://yuanhsh.iteye.com/blog/2181938