洗牌算法及其证明
问题定义:
给定有序序列1-n,要求将其打乱,使得每个元素在任意位置出现的概率均为1/n。
程序实现:
void shuffle(int *arr, int n) // n为序列中元素总数 { int idx; for(int i = 0; i < n; i++) { idx = rand() % (i+1); // idx在下标[0, i]内 swap(&arr[idx], &arr[i]); } }
数学归纳法证明:
(1)当n=1时,idx必为0,所以元素arr[0]在任何一个位置的概率为1/1,命题成立。
(2)假设当n=k时,命题成立,即n=k时,原数组中任何一个元素在任何一个位置的概率为1/k。
(3)则当n=k+1时,由以上假设知,当算法执行完k次时,前k个元素在前k个位置的概率均为1/k;
当执行最后一步时,前k个元素中任何一个元素被替换到第k+1位置的概率为:(1-1/(k+1)) * 1/k = 1/(k+1);
在前面k个位置任何一个位置的概率为(1-1/(k+1)) * 1/k = 1/(k+1);
故前k个元素在任意位置的的概率都为1/(k+1);
所以,对于前k个元素,它们在k+1的位置上概率为1/(k+1)。
对于第k+1个元素,其在原位置的概率为1/k+1,在前k个位置任何一个位置的概率为:(1-1/(k+1)) * (1/k) = 1/(k+1),所以对于第k+1个元
素,其在整个数组前k+1个位置上的概率也均为1/k+1。
(4)综上所述,对于任意n,只要按照方案中的方法,即可满足每个元素在任何一个位置出现的概率均为1/n。