随机取样问题
随机取样问题
输入包括两个整数m和n其中m>n,输出是0-m-1范围内的n个随机整数的有序列表,不允许重复。希望得到没有重复的有序选择,其中每个选择出现的概率相等
#include<iostream> using namespace std; int main() { int n = 10; int m = 100; int selected = n; int remaining = m; srand(time(0)); for(int i=0;i<m;i++) { if(rand()%(m-i) < n) { cout<<i<<" "<<m<<" "<<endl; n--; } } return 0; }
当目标改为随机抽取n个有序整数
该算法时间和m成正比,当m很大而n很小时不合适
将算法啊改成在初始为空的集合里面插入随机整数,直到个数足够
#include<iostream> #include<set> using namespace std; int main() { int n = 10; int m = 100; int selected = n; int remaining = m; srand(time(0)); set<int> s; while(s.size()<n) { s.insert(rand()%m); } set<int>::iterator ite; for(ite=s.begin();ite!=s.end();ite++) { cout<<*ite<<endl; } return 0; }
利用set的特性,每个元素在set中只出现一次,因此在插入时无需判断是否已经插入过。
并且自动排序,输出时已经是有序的
但是插入操作每次都需要对红黑树进行调整,时间主要消耗在建立集合中
另一种方法:
将包含n个数的数组顺序打乱,然后把前m个元素排序输出
实际上只需要打乱前m个元素即可
void genshuf(int m, int n) { int i, j; int *x = new int[m]; for(i=0;i<m;i++) x[i]=i; for(i=0;i<n;i++) { j = randint(i, n-1); swap(x[i], x[j]); sort(x, x+n); }
参考:编程珠玑