遍历数组,遇到第i个元素时,产生一个i到n-1之间的随机数,然后两个位子的数互换。
void shuff(int *ap, int n)
{
int i;
for (i=0; i<n; i++)
{
int t = rand()%(n-i)+i;
swap(a[i],a[t]);
}
}
第一个元素所在的位置为ap+0,这个位置上,应该每个数字出现的概率均为1/n。第一次交换时,rand函数产生的数字范围就是0到n-1,因此确实每个数字都有可能换到ap+0这个地方。对于ap+1,数字出现的概率为: (n-1)/n * 1/(n-1) =1/n 第一次没有被换到ap+0的概率 乘以 第二次被换到ap+1位置的概率。
因此,随机性是满足的~
PS:如果要求所有元素都不在开始的位置上,那就在产生随机位置的时候,除去自己的位置即可。
原本是从i到n-1选一个,现在从i+1到n-1中选一个就行了。
现在有N个位置,按照顺序排列,申请一个一维数组来存储。对于从0至N-1的树i,按照从小到大的顺序,利用随即数随机选取一个从i+1至N-1的数来与第i个数交换位置。这样利用线性时间就完成了操作,也不存在开寻址的问题,因为全部是交换操作。
下面来说明其中的三个问题:
1.每个数都不在自己原来的位置了。这是显然的,因为第i次交换时,如果这个位置上为i,则它会被换到后面去,由于之后不再进行对位置i的操作,所以,这个位置将不会再变化了;如果这个位置上不为i,则之间肯定被换到位置i之前了,那么再换过来的也肯定不会是i。
2.这个算法不会把结果限制在一个小区域内。这也是显然的,对于任意一种排列,实际上,如果我每次对序列的操作都选择排列上相应位置的数来交换就行了。
3.这个算法对生成任意满足条件的排列都是等概率的。这也是显然的。