有一个长度为n的数组,想对其中的元素进行洗牌,使他们能够随机的分布,随机的意思是使每个元素在每个位置上出现的概率都是1/n。
如何去做呢,有一个方法如下:
依次遍历所有的元素,在遍历到第i个元素的时候,有1/i 的概率和前i个元素(包括第i个)其中之一进行交换,则遍历完所有的元素之后,
得到的新的数组就满足上面提到的随机分布的条件。
写成代码如下:
证明如下:
1、当只有1个元素的时候,他的概率是1/1
2、当有2个元素的时候,遍历到第2个元素的时候,有1/2的概率与前2个元素交换,则第1个和第2个元素出现在第1个位置和第2个位置的概率都是1/2
3、k+1个元素的时候,假设遍历完前k个元素,使前k个元素出现在前k个位置的概率都是1/k,则遍历第k+1个元素的时候,有1/(k+1)的概率与所有k+1个元素之一交换,其出现在第k+1个位置的概率是 1 / ( k + 1 ), 其出现在前k个位置的概率是 1 / ( k + 1 ),而前面k个元素中任一个元素被交换到第k+1个位置的概率是 ( 1 - 1 / ( k + 1 ) ) / k = 1 / ( k + 1 ),而其留在前k个位置中的某一个的概率是 ( 1 - ( 1 / ( k + 1 ) ) / k = 1 / ( k + 1 ),故前k个元素在任意位置的概率都是1 / ( k + 1 )
综上所述,对任意的k,只要按照上面所述的方法,即可满足随机分布的条件。
一道衍生的问题,
给定一个长度未知的数据流,如果从中随机选取N个数。
解决方法:
1、定义一个长度为N的数组,数据流中的前N个数依次放入数组中
2、从第K( K > N )个元素开始,每个元素有N / K的概率替代数组中的任一个元素。
按这个方法进行到最后,则数据流中每个数出现在这个数组中的概率都是 1000 / N,所以这个数组中的1000个数就是解。