本章问题:取样问题,主要讲述一个从0~n-1范围内选择m个随机数(有序的)
方法一:依次考虑0,1,…,n-1之间的每个整数,并通过一个适当的随机测试对每个整数进行选择,一般来说,要从r个剩余的整数中选择s个,那么选择下一个整数的概率为s/r。
//在0~n-1范围内按序随机选择m个整数
RadnomSelect(m,n):
select=m
remaining=n
fori=[0,n)
if (bigrand()%remaining)<select //bigrand()返回一个较大的随机数
print i
select--
remaining—
该方法的时间复杂度为O(n)。
方法二:在一个初始为空的集合(不含重复元素)中插入随机整数,直到个数足够。
while size<m do
t=bigrand()%n
ift is not in S
insert t into S
size++
print the elements of S in sorted order
这里的数据结构S要求可以保证整数有序,不存在重复元素。可以利用C++标准模板库中set表示集合,set底层采用红黑树实现,是一种较平衡的二叉查找树。用C++语言编写的函数如下:
void gensets(int m,int n)
{
set<int> S;
while(S.size()<m)
{
s.insert(bigrand()%n);
}
set<int>::iterator it;
for(it=S.begin();it!=S.end();++it)
cout<<*it<<'\n';
}
方法三:
把0~n-1范围内的整型数组顺序打乱,然后把前m个整数排序输出。
改进:只需打乱数组的前m个元素,然后将前m个整数排序输出。C++代码如下:
void genshuf(int m,int n)
{
int i,j;
int *x=new int[n];
for(i=0;i<n;++i)
x[i]=i;
for(i=0;i<m;++i)
{
j=randint(i,n-1);//生成i~n-1范围内的一个随机数
intt=x[i];
x[i]=x[j];
x[j]=t];
}
sort(x,x+m);
for(i=0;i<m;++i)
cout<<x[i]<<"\n";
}
编程过程的几个重要步骤:
1、 正确理解所遇到的问题。
2、 提炼出抽象的问题。简洁、明确的问题陈述不仅可以帮助我们解决当前遇到的问题,还有助于我们把解决方案应用到其他问题中。
3、 考虑尽可能多的解法。多思考一些可能的解决方案,寻找较优的方法,不仅可以提升程序的效率,还可能会缩短编写代码的时间。
4、 实现一种解决方案。用简单的代码和最有效的操作来实现最终选取的解决方案。