【编程珠玑】读书笔记 第十二章 取样问题
2013-07-16 22:22
399 查看
2013-07-16 21:51:49
本章介绍生成小于[0,n-1]区间内的m个顺序随机数的三种方法。
总结参考:/article/5973089.html
1.问题
抽象后的问题如下:输入两个整数m和n,(m < n).输出0~n-1范围内的m个随机整数的有序列表,不允许重复。
也就是说,要对0~n-1范围内的数字进行选择,每个数字被选中的概率相等.
有两点要注意:不允许重复,结果有序;
2.解决方案
2.1已有知识
利用库函数<stdlib.h>中的rand()函数可以产生0到RAND_MAX范围内的随机整数。
RAND_MAX是在前面头文件中定义的宏,具体大小与实现有关,至少为32767(2^15-1).
两个相关函数:
产生很大随机整数bigrand():RAND_MAX *rand() + rand();实际上就是先产生前15位,再产生后15位,也即rand()<<15 | rand();
产生指定范围随机整数 randint(l,u): rand()%(u-l+1)+l; 产生的数据在[l,u]之间.
(后面对时间复杂度的讨论,都默认rand()需要单位时间)
3.时间效率
RandomGenerateKnuth时间效率:该程序的时间复杂度是与n有关的:O(n),空间上只需要几十个字节。
RandomGenerateUseSet时间效率:set每次插入时间为O(logm),while循环总共进行了m次插入,遍历集合需要O(m).故总时间为O(mlogm).额外的空间需求为set集的大小:O(m).
RandomGenerateUseQsort时间效率:时间上为O(n+mlogm), 一次初始化和排序。空间上也需要O(n).
完整实现代码:
测试结果:
本章介绍生成小于[0,n-1]区间内的m个顺序随机数的三种方法。
总结参考:/article/5973089.html
1.问题
抽象后的问题如下:输入两个整数m和n,(m < n).输出0~n-1范围内的m个随机整数的有序列表,不允许重复。
也就是说,要对0~n-1范围内的数字进行选择,每个数字被选中的概率相等.
有两点要注意:不允许重复,结果有序;
2.解决方案
2.1已有知识
利用库函数<stdlib.h>中的rand()函数可以产生0到RAND_MAX范围内的随机整数。
RAND_MAX是在前面头文件中定义的宏,具体大小与实现有关,至少为32767(2^15-1).
两个相关函数:
产生很大随机整数bigrand():RAND_MAX *rand() + rand();实际上就是先产生前15位,再产生后15位,也即rand()<<15 | rand();
产生指定范围随机整数 randint(l,u): rand()%(u-l+1)+l; 产生的数据在[l,u]之间.
(后面对时间复杂度的讨论,都默认rand()需要单位时间)
3.时间效率
RandomGenerateKnuth时间效率:该程序的时间复杂度是与n有关的:O(n),空间上只需要几十个字节。
RandomGenerateUseSet时间效率:set每次插入时间为O(logm),while循环总共进行了m次插入,遍历集合需要O(m).故总时间为O(mlogm).额外的空间需求为set集的大小:O(m).
RandomGenerateUseQsort时间效率:时间上为O(n+mlogm), 一次初始化和排序。空间上也需要O(n).
完整实现代码:
#include <iostream> #include <cassert> #include <set> #include <ctime> using namespace std; const int MaxLength = 10000000; //输入合法性检查 void CheckInvalid(int array[],int len) { assert(NULL != array && len > 0); } //产生大的随机数 int BigRandomGenarate() { return ( RAND_MAX * rand() + rand() ); //对C语言,rand()函数需包含头文件#include<stdlib.h>,但在C++中包含iostream即可 } //产生在[lowBound,upperBound - 1]区间的随机数 int RandomIntGenerate(int lowBound, int upperBound) { return (lowBound + (RAND_MAX * rand() + rand()) % (upperBound - lowBound + 1) ); } //qsort对int型数据排序所需的笔记函数 int IntCompare(const void *_p,const void *_q) { int *p = (int *) _p; int *q= (int *) _q; return (*p - *q); } //用Knuth的方法产生随机数,用概率判断数据是否被选择 void RandomGenerateKnuth(int randomArray[],const int lengthOfRandom,const int maxRandomNumber) { int i; int selectedNum = lengthOfRandom; srand( time(NULL) ); //产生rand()函数的种子 for (i = 0;i < maxRandomNumber;++i) { if (BigRandomGenarate() % (maxRandomNumber - i) < selectedNum) { randomArray[lengthOfRandom - selectedNum] = i; --selectedNum; } } } //产生[0,n-1]区间内的随机数,将不重复的问题利用set容器的唯一性解决 void RandomGenerateUseSet(int randomArray[],const int lengthOfRandom,const int maxRandomNumber) { set <int> randomSet; int i; srand( time(NULL) ); //产生rand()函数的种子 while (randomSet.size() < lengthOfRandom) { randomSet.insert(BigRandomGenarate() % maxRandomNumber); } set <int> :: iterator iterSet; i = 0; for (iterSet = randomSet.begin();iterSet != randomSet.end();++iterSet) { randomArray[i++] = *iterSet; } } //通过交换保证不重复,但进行排序来保证是顺序的 void RandomGenerateUseQsort(int randomArray[],const int lengthOfRandom,const int maxRandomNumber) { int i; int *sequenceArray = new int[maxRandomNumber]; int randomTmp; int tmp; srand( time(NULL) ); //产生rand()函数的种子 for (i = 0;i < maxRandomNumber;++i) { sequenceArray[i] = i; } for (i = 0;i < lengthOfRandom;++i) { randomTmp = RandomIntGenerate(i,maxRandomNumber); tmp = sequenceArray[i]; sequenceArray[i] = sequenceArray[randomTmp]; sequenceArray[randomTmp] = tmp; } for (i = 0;i < lengthOfRandom;++i) { randomArray[i] = sequenceArray[i]; } qsort(randomArray,lengthOfRandom,sizeof(int),IntCompare); delete [] sequenceArray; } //显示数组 void DisplayArray(int array[],int len) { CheckInvalid(array,len); for (int i = 0;i < len;++i) { cout<<array[i]<<"\t"; } cout<<endl; } //测试“脚手架” void TestDriver() { int *randomArray = new int[MaxLength]; int lengthOfRandom; int maxRandomNumber; int programToTest; int i; int timeStart = 0; double timeCostAverage = 0; //测试程序编号 cout<<"the identifier of the program is :"<<endl; cout<<"RandomGenerateKnuth : 1"<<endl; cout<<"RandomGenerateUseSet : 2"<<endl; cout<<"RandomGenerateUseQsort : 3"<<endl; cout<<endl; //输入测试参数 cout<<"please enter the lengthOfRandom and the maxRandomNumber ,end with ctrl+z :"<<endl; cin>>lengthOfRandom>>maxRandomNumber; //输入要测试程序的编号 cout<<"please enter the identifier of the program to test (end with ctrl+z): "<<endl; while (cin>>programToTest) { timeStart = clock(); switch (programToTest) { case 1: cout<<"Test RandomGenerateKnuth..."<<endl; RandomGenerateKnuth(randomArray,lengthOfRandom,maxRandomNumber); break; case 2: cout<<"Test RandomGenerateUseSet..."<<endl; RandomGenerateUseSet(randomArray,lengthOfRandom,maxRandomNumber); break; case 3: cout<<"Test RandomGenerateUseQsort..."<<endl; RandomGenerateUseQsort(randomArray,lengthOfRandom,maxRandomNumber); break; default: break; } timeCostAverage = 1e6 * ( clock() - timeStart ) / ( CLOCKS_PER_SEC); cout<<"the time cost to genarate "<<lengthOfRandom<<" random numbers is : "<<timeCostAverage<<" ms"<<endl; //检查是否是有序的 for (i = 0;i < lengthOfRandom - 1;++i) { if (randomArray[i] > randomArray[i + 1]) { cout<<"sort bug i = "<<i<<endl; } } /*cout<<"the sorted random array is :"<<endl; DisplayArray(randomArray,lengthOfRandom);*/ cout<<endl; cout<<"please enter the identifier of the program to test (end with ctrl+z): "<<endl; } delete [] randomArray; //释放空间 } //主函数 int main(void) { TestDriver(); return 0; }
测试结果:
the identifier of the program is : RandomGenerateKnuth : 1 RandomGenerateUseSet : 2 RandomGenerateUseQsort : 3 please enter the lengthOfRandom and the maxRandomNumber ,end with ctrl+z : 1000000 10000000 please enter the identifier of the program to test (end with ctrl+z): 1 Test RandomGenerateKnuth... the time cost to genarate 1000000 random numbers is : 2.764e+006 ms please enter the identifier of the program to test (end with ctrl+z): 2 Test RandomGenerateUseSet... the time cost to genarate 1000000 random numbers is : 2.5582e+007 ms please enter the identifier of the program to test (end with ctrl+z): 3 Test RandomGenerateUseQsort... the time cost to genarate 1000000 random numbers is : 3.255e+006 ms please enter the identifier of the program to test (end with ctrl+z): ^Z 请按任意键继续. . .
相关文章推荐
- 【编程珠玑】第十二章 取样问题
- 【编程珠玑】第十二章 取样问题
- 编程珠玑: 12章 取样问题 12.3设计空间,程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。 解法2-------解题总结
- 编程珠玑: 12章 取样问题 12.1程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。 优化解法-------解题总结
- 【编程珠玑-读书笔记】用位图解决排序问题--仔细分析问题的重要性
- 12、编程珠玑笔记十二取样问题
- [编程珠玑]取样问题
- 编程珠玑 12 取样问题
- 编程珠玑: 12章 取样问题 12.3设计空间,程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。 -------解题总结
- 【编程珠玑】读书笔记 时空开销模型
- 【编程珠玑】读书笔记 第六章 程序性能分析
- 《编程珠玑》--读书笔记12章:取样问题
- n元一维向量旋转问题(编程珠玑--第2章--问题B )
- 编程之美 - 读书笔记 - 一摞烙饼的排序问题
- 第十二章 取样问题
- 编程之美 - 读书笔记 - 饮料供应问题
- 【编程珠玑】读书笔记 第一章 开篇
- 编程珠玑开篇--磁盘文件排序问题
- 【读书笔记】并发编程需要注意的几个典型问题
- C++ 编程规范101读书笔记(1)组织和策略问题