编程珠玑中关于二分查找的使用
来源:互联网 发布:抓包分析软件 编辑:程序博客网 时间:2024/05/28 22:11
编程珠玑的第二章给我们提出了这样的一个问题。描述如下:
“ 给定一个包含32位整数的顺序文件,它至多包含40亿个这样的整数,并且次序是随机的。请查找一个此文件不存在的32位整数。”
根据鸽巢原理,32为整数,可以有2^32>40亿个数,所以一定存在一个整数,它在这40亿个整数中不存在。这里分两种解法。1:在内存充足的情况下,我们可以使用位图的方法,初始化2^32个位,都为零,依次读入40亿个整数,整数存在,位标1,不存在标0,最后检查位图中为零的下标,就是我们遗漏的数。但是这样做的缺点很明显。程序至少需要2^32/8个字节。相当于500MB内存。2:在内存只有几百个字节的情况下,书中给了我们解决方法,使用二分法(这里的二分法不要求文件中的元素有序,很巧妙的使用哦!)
首先给出文件中最大数和最小数。对于一个32位整数(为了方便,我们默认为无符号的,有符号的比较复杂,我没有想出解决办法哈。囧)最小值是0,最大值是2^32-1。使用二分法解决上述问题步骤如下:
step1:依次读入顺序文件(这里我要特别说明下,这里的顺序文件是指数据的存储方式是顺利的,并不是里面的数据是有序的!我看过很多人写的关于这道题的答案,都是默认数据有序。这是不对的,也是违背了作者的本意)
step2:判断读入的数据在二分法的哪个区间,如果读入的数据left=<temp && temp<= right,那么这个数属于左区间,写入到文件file1中,否则写入文件file2中
step3:判断file1和file2中那个元素少,元素少的那个一定包含我们需要找的遗漏数。那我们就对这个包含元素少的文件重新使用二分法。直到最后的文件中包含的元素只有一个,那么这个元素-1就是我们需要找的那个数(其实遗漏的数字很多,但是使用这个方法只可以找出一个出来)。
举个例子来说。为了方便,我们用数组举例子int a[9]={0,1,2,4,5,6,7,8,9}.我们使用上述方法的求解过程如下:这里left = 0,right = 9,第一次使用二分法,程序把数组分为两个部分。第一部分是{0,1,2,4,},第二部分是{5,6,7,8,9}。由于第一部分的元素较少。那么对第一部分继续使用二分法。注意这时候的right = (left+right)/2 = 4.5.。继续使用二分法,将{0,1,2,4}又分为两个部分{0,1,2}和{4},找到最终的文件{4},只包含一个元素,这个元素左边的数,即4-1就是3,即是我们需要找的数。程序的复杂度是o(n+n/2+n/4+n/8+n/16) = o(2n)。
代码如下:
#include <iostream>#include <fstream>#include <cmath>#include <cstdlib>using namespace std;int main(){//分别是读入的文件,写入的两个文件名string infilename = "file.txt"; //初始化读入文件的名称.long long int temp; long long int left = 0; //文件中存储的数值的最小值应该大于等于leftlong long int right = 14; //文件中存储的最大值应该小于等于 rightlong int non_existent; //这个就是文件中不存在的那个数字,找到并输出int file1count,file2count; //记录二分法,两个部分中每个含有的元素个数int size; //record the final number of the file.while size < 1,break;while(true){//每次重新读取文件的时候,两个二份文件的数目都要归零.file1count = file2count = 0;ifstream infile(infilename); //每次读入的文件都是经过二分法后元素较少的那个文件,当然第一次读取的是整个文件if (!infile.is_open()){cerr << "读取文件操作失败" << endl;exit(0);}ofstream outfile1("file1.txt"); //将经过二分法筛选的元素分别存入file1.txt和file2.txt中ofstream outfile2("file2.txt");if (!outfile1.is_open() || !outfile2.is_open()){cerr << "写入文件操作失败" << endl;exit(0);}while(infile >> temp){ if (temp >= left && temp <= (left+right)/2){ file1count ++;outfile1 << temp << " ";}else {file2count ++;outfile2 << temp << " ";}}infile.close();outfile1.close();outfile2.close();if (file1count < file2count){ //遗漏的整数在outfile1中至少包含一个size = file1count;// 把包含遗漏的元素的那个文件中元素个数赋值给sizeofstream outfile("temp.txt",ios::out); //并且把包含遗漏元素的文件作为新的读入文件ifstream infile("file1.txt",ios::in|ios::_Nocreate); if (!outfile.is_open() || !infile.is_open()){cerr << "读取文件出现错误";exit(1);}right = (left + right)/2; //二分法的经典步骤while(infile >> temp){outfile << temp << " ";}outfile.close();infile.close();}else { //同理size = file2count;ofstream outfile("temp.txt",ios::out); ifstream infile("file2.txt",ios::in|ios::_Nocreate); if (!outfile.is_open() || !infile.is_open()){cerr << "读取文件出现错误";exit(1);}left = (left + right)/2;while(infile >> temp){outfile << temp << " ";}outfile.close();infile.close();}infilename = "temp.txt";if (size <= 1){ //当文件里面的整数小于一个时候,循环结束了。这时候需要找出,漏掉的那个数,可能不止一个,需要判断漏掉的那个数是在temp.txt存贮的左边还是右边.然后输出,经过测试应该是左边。哈哈,程序完成了infile.open("temp.txt");if (!infile.is_open()){cerr << "读取文件失败";exit(1);}infile >> temp; //当最终二分到只剩下一个元素时,将这个元素减去一就是我们需要找的那个文件中没有的那个数non_existent = temp - 1;break;}}cout << "找到一个文件中不存在的数: " << non_existent << endl;return 0;}
程序运行需要的内存很小哦。虽然我没用四十亿个数据测试,但是我用的小数据测试结果是正确的。如果错误,敬请提出,谢谢,QQ1527927373
另外程序参考了点击打开链接。
- 编程珠玑中关于二分查找的使用
- 【编程珠玑】第二章 二分查找的巧妙应用
- 【编程珠玑】第二章 二分查找的巧妙应用
- 《编程珠玑》第二章2.1 二分查找不存在的数
- c++二分查找—来自编程珠玑
- 二分查找递归实现--【编程珠玑】
- 二分查找非递归实现--【编程珠玑】
- 二分查找另类--【编程珠玑第四章】
- 面试算法: 隐藏在《编程珠玑》中二十年的bug及二分查找法的实现
- 编程珠玑第9章二分搜索(有重复数字)中查找某数出现的第一个位置
- 关于编程珠玑中习题2.3的一点思考
- 由July师兄二分查找代码及编程珠玑有感:循环不变性(断言)证明程序的正确性及发现bug
- MTK中使用的二分查找
- 模式识别-查找向量中元素之和最大的连续子向量---编程珠玑
- 关于编程珠玑第一章的体会
- 编程之美系列之关于数组的二分查找
- 编程珠玑之二分搜索
- 《编程珠玑》--关于编程过程中几个重要阶段的摘录
- Android 使用 Ant 批量打包
- MVC和MVP
- OpenGL Programming Guide- Red Book 例子程序库 -系列- 1-Introduction to OpenGL-Part1
- [LeetCode]Search a 2D Matrix
- 父类指针向子类指针的强制类型转换
- 编程珠玑中关于二分查找的使用
- Java设计模式之代理模式
- 如何让优秀的程序员更进一步
- 技术网站网站推荐
- 80X86寄存器介绍
- 手机病毒满10年 高风险移动app突破二百万
- 让人心动的jQuery插件和HTML5动画
- Listview动态加载数据
- win7桌面上的文档编辑后,会改变位置处理办法