2.7 洗牌算法
出自数据结构与算法分析--C语言描述 习题2.7
在有个函数int rand(int n)返回1-n之间的随机数。如何把数组A[N]打乱?
最初的Fisher–Yates算法是在另外开辟一个数组B[N],把打算后的A[N]放到B[N]中,步骤如下
设i=0
1、生成1-A.length长度之间的随机数k
2、把A[k]放到B[i],去除数组A中的A[k],i++。
3、如果A.length>0,转到第1步。
这个算法要去除A中的数,每次要移位,所以算法复杂度为O(N^2)。
例如一个算法过程如下:
随机数范围 | 随机数 | A | B |
---|---|---|---|
1 2 3 4 5 6 7 8 |
随机数范围 | 随机数 | A | B |
---|---|---|---|
1–8 | 3 | 1 2 |
3 |
随机数范围 | 随机数 | A | B |
---|---|---|---|
1–7 | 4 | 1 2 |
3 5 |
随机数范围 | 随机数 | A | B |
---|---|---|---|
1–6 | 5 | 1 2 |
3 5 7 |
1–5 | 3 | 1 2 |
3 5 7 4 |
1–4 | 4 | 1 2 |
3 5 7 4 8 |
1–3 | 1 | 3 5 7 4 8 1 | |
1–2 | 2 | 3 5 7 4 8 1 6 | |
3 5 7 4 8 1 6 2 |
后来算法有了改进,不是另外开辟数组,而是来交换数组A上面的元素来达到重排。
这个算法有2个版本,原理一样:
版本1:
- for(int i = n; i>=1; --i)
- {
- int j=rand(i);//生成1-i之间的随机数
- exchange(A[i],A[j]);//交换A[i],A[j]
- }
版本2:
- for(int i = 1; i <= n; ++i)
- {
- int j=(rand(n)/n)*(n-i+1)+i-1;//生成i-n之间的随机数
- exchange(A[i],A[j]);//交换A[i],A[j]
版本1的一个演算过程如下:
Modern method[edit]
We'll now do the same thing using Durstenfeld's version of the algorithm: this time, instead of striking out the chosen numbers and copying them elsewhere, we'll swap them with the last number not yet chosen. 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 |
参考:http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle