等概率随机洗牌算法

    洗牌问题(shuffle)就如随机取样(random sample)问题,在《计算机程序设计艺术》(volume 2 chapter 3)中得到了详细的讲解,关于该问题的详细探讨可以翻阅该书相应章节。

    洗牌问题,顾名思义,就是给你一把牌,让你把它完全打乱,这可以归结成一个数组问题:

    给你一个长度为n的数组,要求你将其完全打乱,数组中元素交换跟下标是一一对应的,所以也就可以表述为给你一个有序序列0—n-1,要你将其完全打乱,要求每个元素在任何一个位置出现的概率均为1/n。

 

    洗牌问题是打乱一个有序序列(比如下标有序)的算法与随机取样颇有渊源,算法也与随机取样问题十分相近,如下:

 

void shuffle(T* arr, int len)

{

               for(int i=0; i<len; i++)

               {

                               int idx=rand()%(i+1);

                               swap(arr[idx], arr[i]);

               }

}


    上述代码中的做法其实就是蓄水池抽样的思想,即以概率i/(i+1)将数组的第(i+1)个元素换入数组前i个元素组成的蓄水池中。

 

    算法正确性证明也可以用数学归纳法证明:

    待证明问题:对于一个长度为n的数组,经过上述算法处理后,会得到一个随机数组,原数组中每一个元素在任何一个位置的概率均为1/n

 

证明:算法可以分为两部分:前n-1次执行+最后一次执行

1、当n=1时,idx必为0,所以元素arr[0]在任何一个位置的概率为1/1,命题成立。

2、假设当n=k时,命题成立,即n=k时,原数组中任何一个元素在任何一个位置的概率为1/k。

      当n=k+1时,当算法执行完k次时,前k个元素在前k个位置的概率均为1/k,执行最后一步时,前k个元素中任何一个元素被替换到第k+1位置的概率:

      第k+1个元素被选入蓄水池的概率k/(k+1 ) 乘以 前k个元素任意一个被替换的概率1/k,即    (k/(k+1)) * (1/k) = 1/k+1

所以,对于前k个元素,它们在k+1的位置上概率为1/k+1,在前面k个位置任何一个位置上的概率为 其出现在前k个位置上的概率1/k 乘以 其没有被替换到第k+1位置的概率,即 (1/k)* (1-1/(k+1))  =1/(k+1)。 因此,对于前k个元素,其在整个数组前k+1个位置上的概率均为1/k+1;

 

      对于第k+1个元素,其在原位置的概率为1-(k /(k+1))=1/(k+1),在前k个位置任何一个位置的概率为:(k/k+1) * (1/k)=1/(k+1),所以对于第k+1个元素,其在整个数组前k+1个位置上的概率也均为1/k+1。

 

综上1、2两点,命题即可得证。

 

     以上资料,参考自:http://hi.baidu.com/liangrt_fd/item/a9db0ac4afc8e2c8984aa04d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值