取样问题-获取随机样本

需求:在n份的调查中随机获取m份样本(m<=n),设计程序完成。并且m个样本中没有重复。

第一种解决方案:

根据概率论的知识:我们假设(n=5,m=2),我们选择数字0的概率为:2/5。可以用下面语句实现:

if((rand() % 5) < 2)

当我们在 选择0的概率下选择1的概率为1/4,在没有 选择0的概率下选择1的概率为2/4,可以分别通过下面语句实现。

//选择0 那么 m--,同时n--
if((rand() % (n-1) < m-1)
//没有选择0 只需要n--
if((rand() % n < m)

所以,我们只需要通过遍历样本的n元素,然后分别判断概率即可获得,m个随机数。实现代码如下:

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
   srand((unsigned)time(NULL));
   int m = 5;
   int n = 20;

   for(int i=0; i<n; i++)
   {
        if(rand()%(n-i) < m)
        {
            cout<<i<<endl;
            m--;
        }
   }
    return 0;
}

程序输出如下:


分析:该算法需要遍历整个集合的n个样本,时间复杂度为O(n),空间复杂度为O(m)。


第二种解决方案:

可以使用C++模板库中的set集合,来实现无重复元素的插入,思路比较清晰,实现如下:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <set>

using namespace std;

int main()
{
   srand((unsigned)time(NULL));
   int m = 5;
   int n = 20;

   set<int> S;
   while(S.size() < m)
        S.insert(rand() % n);
   
   set<int>::iterator it;
   for(it=S.begin(); it!=S.end(); ++it)
        cout<<*it<<" ";

   cout<<endl;
    return 0;
}
程序运行结果:

分析:该算法使用STL的关联容器set集合,而set使用红黑树实现的,红黑树又能保证在最坏的情况下每次插入新元素只需要 O(logm) 的时间,而遍历集合需要 O(m) ,所以需要 O(m log m) 的时间复杂度,但是所需要数据结构的开销比较大。


第三种解决方案:

思路:因为需要的是m(m<=n)个元素,所以只需要将前m个元素的顺序打乱(通过产生一个随机数,交换他俩的位置来实现),然后排序输出,前m个元素的内容就可以。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <set>
#include <algorithm>

using namespace std;

const int m = 5;
const int n = 20;

int main()
{
   srand((unsigned)time(NULL));
  
   int *x = new int[n];
   for(int i=0; i<n; ++i)//初始化n个元素值
        x[i] = i;

    int ran;
    int tmp;
    for(int i=0; i<m; ++i)
    {
         ran = i + rand()%(n-1-i);//产生一个随机数[i, n-1),包括它本身。
         tmp = x[i];
         x[i] = x[ran];
         x[ran] = tmp;
    }

    sort(x, x+m);

    for(int i=0; i<m; i++)
        cout<<x[i]<<" ";
    cout<<endl;


    return 0;
}

程序输出:3 8 12 14 17  [Finished in 0.1s]

分析:初始化n个元素需要O(n)的时间及空间,以及O(m log m)的排序时间,所以的效率不如第一种方法。

三种方法的总结:

第一种需要遍历整个n所以适合当m较大时,即(m>n/2)

第二种方案的复杂度跟m关系很大,所以适合当m较小的时候。

第三种方案:两种都比较适合,比如说我们需要n为100万时,m为n-10时,我们只需要生成10个数,然后把剩下的数字排序输出就可以。


参考:《编程珠玑》第十二章 取样问题。

开始研究boost。++


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值