编程珠玑之取样问题

来源:互联网 发布:mac笔记本右键怎么按 编辑:程序博客网 时间:2024/04/29 07:33

要从0~n-1的整数中取出来m(m<n)个整数。
有几种算法,第一种算法是严格按照概率得到,满足每个数取得的概率相同。原理和抓阄时候一样,先取和后取得并没有概率上的差别,第一个数字0取得的概率为m/n,当rand()%n<m的时候取得0。以后要调整m和n的值,才可以使得取得的概率相同,这种方法容易理解,并且严格满足m/n的条件。

第二种算法和以前一篇的洗盘算法比较相似,但是并不是严格的每个数字取到的概率为m/n,算法是这样的,先生成一个n维的整数数组,a值为0~n-1,然后生成m个n内的随机整数rand,然后交换a[i]和a[rand](i=0...m-1)。至于是否是满足m/n证明好像有点难。

第三种算法更加直接,用一个set容器存放产生的随机整数,一直产生n内的随机整数填入容器,一直到set的size为m的时候即可。

对于三种算法,如果要求产生的整数为有序的,那么第二第三中算法还有排序,第一种算法是自然有序的,但是当n较大的时候,第一种算法运行的时间可能比较长。对于第一种算法,当n较大,m较小的时候,可以判断下m是否为0,如果为零可以跳出循环。还有别的情况,如果n和m都很大,而且m很接近n的时候,那么可以产生n-m个n内的随机整数,然后输出没有产生的随机整数。还有当n为2的32次方,m为1000万的时候,这种情况,可以直接生成1100万个随机的整数,然后去除重复的整数得到1000w个随机整数。注意RAND_MAX可能小于2的32次方,这时候就要对rand()函数进行改写,假设RAND_MAX为2的31次方,那么可以写个bigRand(){return rand()+rand()};

[cpp] view plaincopy
  1. #include <iostream>  
  2. #include <set>  
  3. using namespace std;  
  4.   
  5. //rand()函数生成一个0到RAND_MAX(stdlib.h中定义的值为2147483647(有符号整数的最大值))之间的整数  
  6. void rand_select1(int n, int m);//在0~n内选择出m个整数  
  7. void rand_select2(int n, int m);  
  8. void rand_select3(int n, int m);  
  9. void exchange(int *a, int i, int j);  
  10.   
  11. int main()  
  12. {  
  13.         //rand_select1(30, 2);  
  14.         //rand_select2(30, 2);  
  15.         rand_select3(30, 2);  
  16.         return 0;  
  17. }  
  18.   
  19. void rand_select1(int n, int m)  
  20. {  
  21.         srand(time(0));  
  22.         for(int i=0; i<n; i++)  
  23.         {  
  24.                 if(rand()%(n-i) < m)  
  25.                 {  
  26.                         printf("%d\n", i);  
  27.                         m--;  
  28.                 }  
  29.         }  
  30. }  
  31.   
  32. void rand_select2(int n, int m)  
  33. {  
  34.         srand(time(0));  
  35.         int *a = new int[n];  
  36.         for(int i=0; i<n; i++)  
  37.                 a[i] = i;  
  38.         for(int i=0; i<m; i++)  
  39.                 exchange(a, i, rand()%n);  
  40.         for(int i=0; i<m; i++)  
  41.                 printf("%d\n", a[i]);  
  42. }  
  43.   
  44. void rand_select3(int n, int m)  
  45. {  
  46.         srand(time(0));  
  47.         set<int> S;  
  48.         while(S.size()<m)  
  49.                 S.insert(rand()%n);  
  50.         set<int>::iterator i;  
  51.         for(i=S.begin(); i!=S.end(); ++i)  
  52.                 printf("%d\n", *i);  
  53. }  
  54.   
  55. void exchange(int *a, int i, int j)  
  56. {  
  57.         int temp = a[i];  
  58.         a[i] = a[j];  
  59.         a[j] = temp;  
0 0
原创粉丝点击