取样问题——《编程珠玑》读书笔记
2012-05-15 11:10
369 查看
问题描述:
给定一个足够大的随机选择函数rand(), 对于[0, n)范围内的数,随机选取m个(m<n),且取出的m个数有序排列(增序或减序)。
问题解答:
1、 一开始拿到问题的时候,我的想法就是从rand()%n中取出m个不同的数。这其中需要解决的问题一个就是如何去重,另一个是排序问题。
作者的算法参考自《The Art of Computer Programming. Volume2: Seminumerical Algorithms》,考虑方向完全不一样。
该算法依次考虑整数0,1,2……n-1,并通过一个适当的随机测试对每个整数进行选择。通过按序访问整数,可以保证输出结果的有序性。
为了理解选择的标准,我们考虑下m=2, n=5的情况。那么我们需要对每个整数的选取概率定为2/5,并且要保证一定能选出2个数出来。
首先我们会考虑整数0,选择0的概率为2/5,可以通过下面的语句来实现:
if (rand() % 5) < 2
不幸的是,我们不能用同样的概率来选择整数1:这样做的话我们从5个整数中选出的整数可能是两个也可能不是两个。因此决策有一些不同:在已经选择0的情况下以1/4的概率选择1, 而在没有0的情况下一2/4的概率选择1(我们来看下选择1的概率是多少:2/5 * 1/4 + 3/5 * 2/4 = 2/5,使我们需要的概率)。一般说来,如果要从r个剩余的整数中选出s个,我们以概率s/r选择下一个数。
下面是完整的C代码,可参考
2、顺带附上刚开始的想法,时间复杂度为O(mlogm):
3.
生成随机数另一种方法是把包含整数0~n-1的数组顺序打乱,然后把m个元素排序输出。Ashley Shepherd和Alex Woronow发现,在这个问题中我们只需要打乱数组的前m个元素,时间复杂度为O(n)
给定一个足够大的随机选择函数rand(), 对于[0, n)范围内的数,随机选取m个(m<n),且取出的m个数有序排列(增序或减序)。
问题解答:
1、 一开始拿到问题的时候,我的想法就是从rand()%n中取出m个不同的数。这其中需要解决的问题一个就是如何去重,另一个是排序问题。
作者的算法参考自《The Art of Computer Programming. Volume2: Seminumerical Algorithms》,考虑方向完全不一样。
该算法依次考虑整数0,1,2……n-1,并通过一个适当的随机测试对每个整数进行选择。通过按序访问整数,可以保证输出结果的有序性。
为了理解选择的标准,我们考虑下m=2, n=5的情况。那么我们需要对每个整数的选取概率定为2/5,并且要保证一定能选出2个数出来。
首先我们会考虑整数0,选择0的概率为2/5,可以通过下面的语句来实现:
if (rand() % 5) < 2
不幸的是,我们不能用同样的概率来选择整数1:这样做的话我们从5个整数中选出的整数可能是两个也可能不是两个。因此决策有一些不同:在已经选择0的情况下以1/4的概率选择1, 而在没有0的情况下一2/4的概率选择1(我们来看下选择1的概率是多少:2/5 * 1/4 + 3/5 * 2/4 = 2/5,使我们需要的概率)。一般说来,如果要从r个剩余的整数中选出s个,我们以概率s/r选择下一个数。
下面是完整的C代码,可参考
#include <iostream> #include <stdlib.h> using namespace std; int genknuth(int m, int n) { for (int i = 0; i < n; i++) { if ((rand() % (n - i)) < m) { cout << i << "\t"; m--; } } cout << endl; return 0; } int main() { genknuth(10, 101); return 0; }
2、顺带附上刚开始的想法,时间复杂度为O(mlogm):
int gensets(int m, int n) { set<int> s; while (s.size() < m) { s.insert(rand() % n); } set<int>::iterator i; for (i = s.begin(); i != s.end(); i++) { cout << *i << "\t"; } cout << endl; return 0; }
3.
生成随机数另一种方法是把包含整数0~n-1的数组顺序打乱,然后把m个元素排序输出。Ashley Shepherd和Alex Woronow发现,在这个问题中我们只需要打乱数组的前m个元素,时间复杂度为O(n)
int intcmp(const void* it1, const void* it2) { return *(int*)it1 - *(int*)it2; } int randrange(int a, int b) { return (rand() % (b -a)) + a; } int genshuf(int m, int n) { int i, j; int* x = new int ; for (i = 0; i < n; i++) { x[i] = i; } int t; for (i = 0; i < m; i++) { j = randrange(i, n - 1); t = x[i]; x[i] = x[j]; x[j] = t; } qsort(x, m, sizeof(int), intcmp); for (i = 0; i < m; i++) { cout << x[i] << "\t"; } cout << endl; return 0; }
相关文章推荐
- 《编程珠玑》--读书笔记12章:取样问题
- 《编程珠玑》阅读小记(9) — 取样问题
- 编程珠玑:取样问题
- 《编程珠玑》阅读小记(9) — 取样问题
- 抽样问题——《编程珠玑》读书笔记
- 取样问题(编程珠玑)
- 插入查找元素效率问题——《编程珠玑》读书笔记
- 编程珠玑 12 取样问题
- 编程珠玑--第12章 取样问题
- 编程珠玑(2)第十二章学习笔记 取样问题
- 编程珠玑:取样问题
- 取样问题——《编程珠玑》学习笔记
- 编程珠玑(三)取样问题
- 连续子向量最大和问题——《编程珠玑》读书笔记
- 编程珠玑第12章(取样问题)学习笔记
- 编程珠玑: 12章 取样问题 12.1程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复-------解题总结
- 编程珠玑之取样问题
- 编程珠玑第十二章--应用之取样问题
- 【编程珠玑】读书笔记 第十二章 取样问题
- [读书笔记]python爬虫-scrapy安装过程常见问题及解决方法