随机取样

问题定义:

输入:两个整数m和n,其中m<n。

输出:[0,n-1]范围内m个整数的有序列表,不允许重复。


1、假如我们拥有一个能返回很大的(远大于m和n)的随机整数的函数bigrand()

顺序考虑整数0...n-1,并通过bigrand()的测试对每个整数进行选择,这样保证输出的数为有序的。

考虑m=2,n=5的情况,选择第一个整数0的概率为2/5,可以通过bigrand() % 5 < 2来以2/5的几率选择整数0;再考虑整数1,不能再以2/5的几率选择,否则不能保证选择的结果一定为两个(虽然这样选择的期望确实为两个),在选择0的情况下以1/4的概率选择1,在未选择0的情况下以2/4的概率选择1。

通过对每个数都以这样的概率进行考虑,可以保证不会选择更多的整数,因为当待选择的个数为0时,选取概率为0;也不会选择更少的整数,当剩余的数个数与待选的数的个数相同时,选取概率为1,必然选择。

 1 void getknuth(int m, int n){
 2     int i;
 3 
 4     for(i=0; i<n; i++){
 5         if(bigrand() % (n-i) < m){
 6             printf("%d ", i);
 7             m--;
 8         }
 9     }
10 }

 2、一个复杂度更低的算法

伪代码如下:

1 initialize set S to empty
2 size = 0
3 while size < m do
4     t = bigrand() % n
5     if t is not in S
6         insert t into S
7         size++
8 print the elements of S in sorted order

3、利用交换随机打乱数组的顺序,选取前m个元素作为结果

randint(i, j)函数返回i...j之间随机整数

伪代码如下:

 1 void genshuf(int m, int n){
 2     int i, j;
 3     int *x = new int[n];
 4     for(i=0; i<n; i++){
 5         x[i] = i;
 6     }
 7     for(i=0; i<m; i++){
 8         j = randint(i, n-1);
 9         swap(i, j);
10     }
11     sort(x, x+m);
12     print the first m elements;
13 }

 

posted @ 2018-03-17 13:25  赵永驰  阅读(201)  评论(0编辑  收藏  举报