编程珠玑之第二章questionA: 40亿个随机排列整数问题
2015-01-02 11:43
260 查看
问题描述:
A. 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数(在文件中至少缺失这样一个数——为什么?)。在具有足够内存的情况下,如何解决该问题?如果有几个外部的“临时”文件可用,但是仅有几百字节的内存,又该如何解决该问题?
问题解析:
1、首先要明白整型代表的范围如下:
![](http://img.blog.csdn.net/20141231150238811?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSm9obm55SHU5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
由此看出一个无符号长整型大约表示43亿个数,所以大约有3亿个数是在此文件中不存在的,这样问题就明确了。
2、怎样生成包含40亿个随机排列的32位整数的顺序文件(假设里面数不重复)呢?
在windows系统下,RAND_MAX = 32767(0x7FFF); 我的Linux下RAND_MAX = 2147483647(0x7FFFFFFF). 在Windows下经过对rand()修改,这个范围可以增大,但由于不知道其实现算法,所以任何改变的都有可能改变输出值的概率,所以效果不是很理想,下面我在范围输出随机数范围[0, 65534],为什么不是65535?
因为我发现任何对rand()改变,其输出随机值的概率(如最大,最小值)都会有很多改变,所以没有找到理想的方法,下面在勉强接受的范围内对上面问题做一个映射。
下面利用位图技术和C++的bitset输出在[0. 65534]范围内不重复的随机数:
输出结果:
![](http://img.blog.csdn.net/20150102113645984?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSm9obm55SHU5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
65535条数据都要这么长时间,跟别说40亿条数据了,所以需要大范围高效的随机数生成函数,C++11对随机数生成改进了不少,也比较复杂,也许可以在获得解答,可以查阅C++11 关于随机数的一些文档,以后有机会在研究!
解决方案:
1. 位图技术:
那么在有足够内存的情况下使用进行排序,查找缺失数就非常方便了!类似的解答可以参考第一章习题的解答:编程珠玑之第一章:开篇(习题)泛览 的习题2解答方案!
2. 二分搜索:
作者给出的方法是0/1探测法下的二分搜索,在不需要对所有数据的进行排序的情况下找出一个缺失的整数,我这里在小范围内做一个实现方案,当然在如此之大(40亿)的情况下还要具体修改。
如下:这里是使用0/1探测法找出所有小于20的缺失的整数:
输出结果如下:
A. 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数(在文件中至少缺失这样一个数——为什么?)。在具有足够内存的情况下,如何解决该问题?如果有几个外部的“临时”文件可用,但是仅有几百字节的内存,又该如何解决该问题?
问题解析:
1、首先要明白整型代表的范围如下:
由此看出一个无符号长整型大约表示43亿个数,所以大约有3亿个数是在此文件中不存在的,这样问题就明确了。
2、怎样生成包含40亿个随机排列的32位整数的顺序文件(假设里面数不重复)呢?
在windows系统下,RAND_MAX = 32767(0x7FFF); 我的Linux下RAND_MAX = 2147483647(0x7FFFFFFF). 在Windows下经过对rand()修改,这个范围可以增大,但由于不知道其实现算法,所以任何改变的都有可能改变输出值的概率,所以效果不是很理想,下面我在范围输出随机数范围[0, 65534],为什么不是65535?
因为我发现任何对rand()改变,其输出随机值的概率(如最大,最小值)都会有很多改变,所以没有找到理想的方法,下面在勉强接受的范围内对上面问题做一个映射。
下面利用位图技术和C++的bitset输出在[0. 65534]范围内不重复的随机数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <iostream> #include <bitset> #include <cstdio> #include <cstdlib> // srand, rand #include <ctime> // time, clock_t #include <cassert> // assert #define MAX_16UINT 65535 // 最大的16无符号整型数(2^16-1) #define MAX_RANDNUM 65000 // 最大的随机数个数 #define error( str ) fatal_error( str ) #define fatal_error( str ) fprintf( stderr, "%s\n", str ), exit( 1 ) using namespace std; /************************************************************************/ // 函数名称:bigrand // 函数目的:生成范围在[0, 65534]之间的随机整数 // 使用条件:RAND_MAX = 32767(0x7FFF) /************************************************************************/ size_t bigrand() { assert(RAND_MAX == 0x7FFF); return rand() + rand(); } bitset<MAX_16UINT> mybits; int main() { mybits.set(); // 默认所有位都置为1 printf("程序开始........\n"); clock_t start_time = clock(); // 开始时间 FILE* iofile = fopen("unsortfile.txt", "w"); if (NULL == iofile){ fatal_error("不能打开unsortfile.txt文件!\n"); } size_t record = 0; while (record != mybits.size()){ size_t index = bigrand(); // 输出值并将指定位置为0 if (mybits[index]){ fprintf(iofile, "%d\t", index); mybits[index] = 0; record++; //printf("reords = %d", record); } // 测试生成最大和最小值概率 if ( index == 0 || index == 65534){ printf("index = %d\n", index); } } fclose(iofile); clock_t end_time = clock(); // 结束时间 float cost_time = (float)(end_time - start_time) / CLOCKS_PER_SEC; printf("bit位记录数:%d\n", mybits.size()); printf("全部it位重置为0耗时:%5.3f秒\n", cost_time); return 0; } |
65535条数据都要这么长时间,跟别说40亿条数据了,所以需要大范围高效的随机数生成函数,C++11对随机数生成改进了不少,也比较复杂,也许可以在获得解答,可以查阅C++11 关于随机数的一些文档,以后有机会在研究!
解决方案:
1. 位图技术:
那么在有足够内存的情况下使用进行排序,查找缺失数就非常方便了!类似的解答可以参考第一章习题的解答:编程珠玑之第一章:开篇(习题)泛览 的习题2解答方案!
2. 二分搜索:
作者给出的方法是0/1探测法下的二分搜索,在不需要对所有数据的进行排序的情况下找出一个缺失的整数,我这里在小范围内做一个实现方案,当然在如此之大(40亿)的情况下还要具体修改。
如下:这里是使用0/1探测法找出所有小于20的缺失的整数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #include <iostream> #include <bitset> #include <vector> #include <cstdio> #include <cstdlib> // srand, rand #include <ctime> // time, clock_t #include <cassert> // assert using namespace std; /************************************************************************/ // 函数名称:getbit // 函数返回:0或1 // 函数目的:找出value的pos比特位的值 // 使用条件:value范围是[0, 2^32-1] /************************************************************************/ bool getbit(int32_t value, int32_t pos) { assert(pos >= 0 && pos < 32); int32_t mask = 1; // 表示二进制掩码 int32_t value_32 = value; return ((value_32 >> pos & mask) == mask); } /************************************************************************/ // 函数名称:find_missing_integers // 函数返回:无 // 函数目的:找出小于max_counts(不包括)的所有缺失的整数 // 使用条件:vecints里面的数不重复, pos=0时,vetints里面最大值小于max_counts /************************************************************************/ bitset<32> bit_missing_integer; void find_missing_integers(const vector<int32_t>& vecints, const int32_t max_counts, int32_t pos=0) { // 计算相应bit位的0,1计数 int32_t counts_0 = 0, counts_1 = 0; counts_0 = ceil(1.0 * max_counts / 2 ); // ceil向上取整 counts_1 = max_counts - counts_0; vector<int32_t> vecints_0, vecints_1; for (size_t i = 0; i != vecints.size(); ++i) { if (!getbit(vecints[i], pos)) { vecints_0.push_back(vecints[i]); } else { vecints_1.push_back(vecints[i]); } } // 第pos位缺1的情况 if (counts_1 - vecints_1.size() > 0){ bit_missing_integer[pos] = 1; find_missing_integers(vecints_1, counts_1, pos + 1); } // 第pos位缺0的情况 if (counts_0 - vecints_0.size() > 0){ bit_missing_integer[pos] = 0; if (counts_0 == 1 && counts_1 == 0){ // 临界位 printf("%ld\t", bit_missing_integer.to_ulong()); return; } else { // 递归调用 find_missing_integers(vecints_0, counts_0, pos + 1); } } return; } void print_missing_integers() { int myints[5] = {1, 19, 4, 6, 18}; std::vector<int> myvecints(myints, myints + sizeof(myints) / sizeof(int) ); find_missing_integers(myvecints, 20); return; } int main() { print_missing_integers(); return 0; } |
相关文章推荐
- 编程珠玑: 12章 取样问题 12.1程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。 优化解法-------解题总结
- 40亿个随机排列整数问题
- 编程珠玑: 12章 取样问题 12.3设计空间,程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。 解法2-------解题总结
- 编程珠玑: 12章 取样问题 12.3设计空间,程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。 -------解题总结
- 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数
- 编程珠玑: 13章 搜索 13.1生成[0 ,maxval]范围内m各随机整数的有序序列 -------解题总结
- 编程珠玑_第十三章_生成一个随机整数的有序集合
- 编程珠玑之第二章questionB: n元一维向量旋转问题
- 《编程珠玑》第二章三个问题A---查找40亿个32位整数中缺失的某个整数
- 编程珠玑 ~~ 排序与随机整数序列
- 在一个包含40亿个随机排列的32位整数的顺序文件中(注意随机排序),找出一个不再文件中的32位整数
- 编程珠玑: 13章 搜索 13.4使用整数结构,生成[0 ,maxval]范围内m各随机整数的有序序列 -------解题总结
- 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数。
- 编程珠玑之第一章习题4: 生成不同的随机顺序的随机整数及存储与读取
- 编程珠玑---读书笔记---生成随机整数的有序子集
- [编程珠玑]取样问题
- 位图法;海量数据处理之位图技巧;位图技巧;海量数据;编程珠玑第二章问题A;40亿整数;腾讯面试题
- C/C++编程常见问题(2)-错误打印64位长整数
- 【编程珠玑】第二章 二分查找的巧妙应用
- 小心编程中整数溢出的问题