均匀随机排列数组

1. 简述

    本文主要是关于均匀随机排列数组的一个学习总结,主要参考资料是算法导论。

2. 相关题目

    据说腾讯一个题目:对于一个斗地主游戏,给出一个发牌的算法,让每个人的牌确保随机。
    分析:考虑假设有N张牌,要分出来M张牌,给K个人。我能想到的是,N张牌有N种排列,随机产生一种排列,将产生排列的前M张牌依次分给K个人。使用均匀随机排列算法,能够保证:对于N张牌的N!种排列,且得到的任意一种排列的概率都是相同的,即都为1/(N!)。

3. 判定方法

    对于一个算法能否保证均匀随机排列数组,主要考查两点:
  · 产生的排列个数是N!个
    · 每种排列的概率相同,即都为1/N!

4. 两个算法

 ·方法一:首先,得到一个优先级数组P,然后根据优先级数组P来排序原数组A。关键在于优先级数组P,要保证能够得到n!种排列,且每种排列的概率相等。   

PERMUTE-BY-SORTING(A)
  n 
<- length[A]
  
for i <- 1 to n // 产生优先级
    do P[i] = RANDOM(1, n*n*n)
  sort A, 
using P as sort keys // 根据优先级排序
  return A

    RANDOM中使用n的立方是为了使得产生的优先级尽量是唯一的,因此对这个方法的证明的前提是分配的优先级是唯一的。
    考虑优先级数组正好是升序的这一个特殊序列,概率为(1/n) * (1/(n-1)) * ... * (1/1) = 1 / (n!)
    对于优先级数组的其他情况,也能得到类似结果(具体看算法导论)。
    因此一共能得到n!个序列,每个序列的概率都是相同的,满足判定方法。
 ·方法二:第一次交换A1与Rand(1,n),第二次交换A2与Rand(2,n),...,第n次交换An与Rand(n,n)   

RANDOMIZE-IN-PLACE(A)
  n 
<- length(A)
  
for i<- 1 to n
    
do swap A[i]<->A[RANDOM(i,n)]

    概率分析忽略了,说实话证明较为复杂,先不看了,下次再说了。
    方法一的时间复杂度为O(N+N*LogN),方法二的时间复杂度为O(N)。

5. 一个反例   

PERMUTE-WITHOUT-IDENTITY(A)
  n-<length[A]
    for i<- 1 to n-1
      do swap A[i] <-> A[RANDOM(i+1, n)]

    感觉上对于升序的概率是:1/(n-1) * 1/(n-2) * ... * 1 = 1 / (n-1)!每个排序的概率都一样,那么也就是只有(n-1)!种排列。其实对于A[i]交换的元素下标是在[i+1, n]这个范围内,即每个元素肯定是与后面的元素交换,不会与自己交换,所以对于A1肯定越交换越往后,无论多少次随机都不会被换到原来的位置了,因此不能保证n!中排列,不是均匀随机排列。 
6. 参考
    算法导论,第二版,5.3节,随机算法,Page58

    腾讯大厦面试经历    http://www.iweber.org/weber/?tag=%e8%85%be%e8%ae%af

posted @ 2011-09-05 15:27  xiaodongrush  阅读(2827)  评论(3编辑  收藏  举报