二分查找(Binary Search)

1.递归实现

int binarySearchRecursive(int a[],int low,int high,int key){if(low>high)return -(low+1);int mid=low+(high-low)/2;if(key<a[mid])return binarySearchRecursive(a,low,mid-1,key);else if(key > a[mid])return binarySearchRecursive(a,mid+1,high,key);elsereturn mid;}int binarySearchRecursive(int a[],int n,int key){return binarySearchRecursive(a,0,n-1,key);
}

 

2.非递归实现

int binarySearch(int a[],int n,int key){int low=0,high=n-1;int mid;while(low<=high){mid=low+(high-low)/2;if(key<a[mid])high=mid-1;else if(key>a[mid])low=mid+1;elsereturn mid;}return -(low+1);
}

 

3.二分查找的一种版本,现实需求中可能需要查找“在不破坏有序的状态的原则下,可插入key的第一个位置”。

/*返回递增数组中第一个不小于key的数的索引,即在不破坏排序状态的原则下,可插入key的第一个位置。
算法思想:循环不变式为a[low]<key&&a[high]>=key,
所以当low+1==high && high<n时,high就应该是第一个大于等于key的数的索引;
但是当high==n,这时就可以判断数组中没有大于等于key的值,则插入位置为high,返回-(high+1);*/
int lowerBound(int a[],int n,int key){int low=-1,high=n;//假设n>=0, a[-1]<key&&a[n]>=key(但是程序并不访问这两个假想的元素)int mid;while(low+1!=high){mid=low+(high-low)/2;if(a[mid]<key)low=mid;//修正low,确保满足循环不变式中a[low]<keyelsehigh=mid;//修正high,确保满足循环不变式中a[high]>=key
    }int index=high;//第一个大于等于key的数的索引/*判断第一个大于等于key的数a[index]是否存在数组中*/if(index>=n||a[index]!=key)//不存在index=-(high+1);//修正index为负的插入位置的后一个位置return index;
}

 

4.二分查找的一种版本,现实需求中可能需要查找“在不破坏有序的状态的原则下,可插入key的最后一个位置”。

/*upperBound试图在已排序数组中寻找可插入key的最后一个合适的位置。
算法思想:循环不变式为a[low]<=key&&a[high]>key,
所以当low+1==high && low>=0时,low就应该是第一个大于key的数的索引;
但是当low<0,这时就可以判断数组中没有小于等于key的值,则插入位置为low+1,返回-(low+1+1)*/
int upperBound(int a[],int n,int key){int low=-1,high=n;//假设n>=0, a[-1]<=key&&a[n]>key(但是程序并不访问这两个假想的元素)int mid;while(low+1!=high){mid=low+(high-low)/2;if(a[mid]<=key)low=mid;//修正low,确保满足循环不变式中a[low]<=keyelsehigh=mid;//修正high,确保满足循环不变式中a[high]>key
    }int index=low+1;//第一个大于key的数的索引/*判断最后一个小于等于key的数a[low]是否存在数组中*/if(low<=-1||a[low]!=key)//不存在index=-(low+1+1);//修正index为负的插入位置的后一个位置return index;
}

 

幸运的是,STL在<algorithm>中实现了这些算法的泛型版本。对应的函数分别为:binary_search, lower_bound, upper_bound

其内部实现非常精妙,详见侯捷的《STL 源码剖析》。当然思想与上文实现大同小异,但是速度方面有待验证。

此外,C库函数也提供了void* bsearch(const void *key, const void *base, size_t n, size_t size, int (*com) (const void *first, const void *second) )。

下面给出以上函数的例子:

#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<ctime>
using namespace std;//print a array with macro
#define printArray(arr,n) for(int i=0;i<n;i++){\cout<<a[i]<<' ';\}\cout<<endl<<endl;\//compare function greater
int greater(const void *first,const void *second){int _first=*static_cast<const int*>(first);int _second=*static_cast<const int*>(second);if(_first>_second)return 1;else if(_first<_second)return -1;elsereturn 0;
}int main()
{srand(time(0));const int n=10;int a[n];for(int i=0;i<n;i++){a[i]=rand()%20;}printArray(a,n);sort(a,a+n);printArray(a,n);int b;b=rand()%20;//b=a[0];//test 1// b=a[n-1];//2printf("searching %d ...\n",b);bool found=binary_search(a,a+n,b);if(found){//foundcout<<"found"<<endl;}else{cout<<"no found"<<endl;}cout<<"\nbsearch"<<endl;void* p=bsearch(&b,a,n,sizeof(int),::greater);if(p!=NULL){//foundcout<<"found "<<*static_cast<int*>(p)<<endl;}else{cout<<"no found"<<endl;}cout<<"\nbinarySearchRecursive"<<endl;int index=binarySearchRecursive(a,n,b);if(index>=0){cout<<"found! And index="<<index<<endl;}else{cout<<"no found! But "<<b<<" should be insert at "<<-index-1<<endl;}cout<<"\nbinarySearch"<<endl;index=binarySearch(a,n,b);if(index>=0){cout<<"found! index="<<index<<endl;}else{cout<<"no found! But "<<b<<" should be insert at "<<-index-1<<endl;}int* bound=NULL;bound=lower_bound(a,a+n,b);cout<<"lower bound: ";if(bound!=NULL){//existcout<<*bound;}else{cout<<"no exist";}cout<<endl;bound=upper_bound(a,a+n,b);cout<<"upper bound: ";if(bound!=NULL&&bound<a+n){//exist. /*这里需要检查bound是否在数组中,因为最大值的upper_bound返回其下一个位置,即a+n。而lower_bound一定指向数组外面。*/cout<<*bound;}else{cout<<"no exist";}cout<<endl;cout<<"\nlowerBound"<<endl;int lIndex=lowerBound(a,n,b);if(lIndex>=0){cout<<"found! The index of lower bound is "<<lIndex<<endl;}else{cout<<"no found! The index of lower bound is "<<-lIndex-1<<endl;}cout<<"\nupperBound"<<endl;int uIndex=upperBound(a,n,b);if(uIndex>=0){cout<<"found! The index of upper bound is "<<uIndex<<endl;}else{cout<<"no found! The index of upper bound is "<<-uIndex-1<<endl;}
}

 

那么这些算法的执行时间又是咋样的呢?

我分别针对数组长度和选中概率(即,数组中数据被选中的概率)做了如下实验:

//生成超过RAND_MAX的大随机数
long bigRand(){return rand()*RAND_MAX+rand();
}int main()
{srand(time(0));//生成测试数组const int n=10000000;long* a=new long[n];for(int i=0;i<n;i++){a[i]=bigRand()%(n*4);//设定选中概率}//生成查找的数值const int times=10000;//测试次数long b[times];for(int i=0;i<times;i++){b[i]=bigRand()%(n*4);}clock_t start,end;//start=clock();sort(a,a+n);//end=clock();//printf("sort eclipse time: %.2f ms\n",double(end-start)*1000/CLOCKS_PER_SEC);
    start=clock();for(int i=0;i<times;i++){binarySearchRecursive(a,n,b[i]);}end=clock();printf("%-30s: %.2f ms\n","binarySearchRecursive",double(end-start)*1000/CLOCKS_PER_SEC);start=clock();for(int i=0;i<times;i++){binarySearch(a,n,b[i]);}end=clock();printf("%-30s: %.2f ms\n","binarySearch",double(end-start)*1000/CLOCKS_PER_SEC);//vector<int> vec(a,a+n);
start=clock();for(int i=0;i<times;i++){//binary_search(vec.begin(),vec.end(),b[i]);lower_bound(a,a+n,b[i]);}end=clock();printf("%-30s: %.2f ms\n","binary_search",double(end-start)*1000/CLOCKS_PER_SEC);start=clock();for(int i=0;i<times;i++){bsearch(&b[i],a,n,sizeof(int),::greater);}end=clock();printf("%-30s: %.2f ms\n","bsearch",double(end-start)*1000/CLOCKS_PER_SEC);delete []a;
}

Debug模式

 选中概率为0.5

选中概率0.5
 执行1000次的总时间(ms)
数组长度binarySearchRecursivebinarySearchlower_boundbsearch
100000001352812
1000000103229
10000062186
1000062155

 

 

 

 

 

  

 

选中概率为0.25

选中概率0.25
 执行1000次的总时间(ms)
数组长度binarySearchRecursivebinarySearchlower_boundbsearch
100000001552813
1000000103218
10000073187
1000052155

 

 

 

 

 

 

 选中概率为0.75的执行时间相似,这里就省略了。

对比以上实验结果,可知Debug模式下binarySearch的执行效率最高,STL中以lower_bound为代表三算法效率最低。可能STL的算法没有被优化调用。

由于实验的时候忘记调成release模式,差点得出了相反的结果。

 

Release模式下binarySearchRecursive,binarySearch,lower_bound全为0,bsearch花费最多时间,可见STL三算法得到了优化调用,而因为正如《编程珠玑》中所述,C库函数的通用接口开销很大。

综上,没有特殊需求,二分搜索可以直接使用STL中lower_bound,upper_bound,binary_search函数。

 

 

转载于:https://www.cnblogs.com/freewater/archive/2013/03/01/2937886.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461324.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

判断一个字符串是否为回文-链队(新建,进队,出队),链栈(新建,进栈,出栈)...

回文&#xff1a;字符对称排列的字符串&#xff0c;例如ABCBA 思路&#xff1a;根据队&#xff1a;先进先出和栈: 先进后出的原则&#xff0c;进行比较出队和出栈的字符是否相等。如果相等&#xff0c;则为回文。 创建控制台应用程序。 1 #region 字符节点类 2 …

字符设备驱动基础5——驱动如何操控硬件

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 补充内容&#xff1a;字符设备驱动高级篇5——静态映射表、动态映射结构体方式操作寄存器 前言 上节字符设备驱动基础4——读写接口的操作实践中&#xff0c;驱动源代码中的test_chrdev_open()、te…

Android----使用代码 建立gprs 闹钟 连接

Android&#xff1a;实用代码&#xff08;开启启动、建立GPRS连接、闹钟等&#xff09; 分类&#xff1a; Android2012-04-21 18:06312人阅读评论(0)收藏举报androidactionstringservice手机j2me1&#xff1a;查看是否有存储卡插入String statusEnvironment.getExternalStorage…

句法依存分析_复旦大学邱锡鹏教授:词法、句法分析研究进展综述

本文为第十六届自然语言处理青年学者研讨会 YSSNLP2019 报告《词法、句法分析研究进展综述》的简要文字整理&#xff0c;本报告主要回顾词法、句法领域的最新研究进展。 关于报告人&#xff1a;邱锡鹏&#xff0c;复旦大学计算机科学技术学院副教授&#xff0c;博士生导师。于复…

【struts2】Struts2的运行流程

1&#xff09;前提条件 在讲解流程之前&#xff0c;假设我们已经建立了的一个名为strutsDeepen的web工程&#xff0c;该工程仅仅实现了简单的用户登陆与欢迎界面。具体的实现为&#xff1a; 在web.xml中配置了Struts2的过滤器写了一个Action类&#xff0c;名称为loginAction在s…

获取系统信息2——linux中使用随机数

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、随机数和伪随机数 随机数是随机出现&#xff0c;没有任何规律的一组数列。真正的完全随机的数列是不存在的&#xff0c;只是一种理想情况。我们一般只能通过一些算法得到一个伪随机数序列。平时…

11. 类对象简介

11. 类对象简介1.1 类是一个模板&#xff0c;是一种类型&#xff0c;“物以类聚”1.2 对象是类的一个具体实现1.3例如&#xff1a;汽车模型和生产出来的汽车猫和我家的那只猫1.4 实例人骑车public class Test3{public static void main(String[] args){Person p new Person();…

python 建筑计算_制图小技巧:巧用Python和ELK瞬间完成总图建筑名称标注

哎呦&#xff0c;又到了每周一次的制图教室啦。经过前面两次制图教程的分享&#xff0c;相信大家对于白模填色和写实渲染这两种表达方式肯定有了较好的掌握。那么今天我们就转战制图技巧篇&#xff0c;和童鞋们聊一下总平面图中的建筑名称标注问题。对于总平面图&#xff0c;各…

在MacOSX上重新安装Python (10.8) python 自然语言处理的前戏

因为想学python自然语言处理就想在mac上重新配置一下python。 在网上找了很久才找到两篇有用的教程http://765i.cn/%E5%9C%A8macosx%E4%B8%8A%E9%87%8D%E6%96%B0%E5%AE%89%E8%A3%85python-10-8/ http://woodpecker.org.cn/diveintopython3/installing-python.html 第一篇文章基…

获取系统信息3——proc文件系统介绍和使用

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、proc文件系统介绍 1、操作系统级别的调试一般很困难 简单的程序可以单步调试&#xff1b;复杂一点的程序可以printf、cout等打印信息调试&#xff08;即输出信息到控制台&#xff09;&#xff0…

阻止函数源码在控制台输出

这是一个很贱的技能&#xff0c;我在谷歌控制台源码里看到的。相信大家都知道&#xff0c;在控制台里只输入函数名&#xff0c;不输入 () 然后按回车&#xff0c;就可以输出源码。 都不会陌生吧&#xff0c;这也有助于我们调试&#xff0c;是个很棒的技巧。不过系统内置的就会输…

值不值得入手_iPhone11现在还值不值得入手?真实用户说出心里话

iPhone11作为苹果走量的一款机型&#xff0c;自发布以来就备受争议&#xff0c;有的朋友说真香&#xff0c;A13iOS只卖4000多&#xff0c;还有的朋友吐槽大黑边、828P的屏幕、信号不好还有充电太慢&#xff0c;特别是现在同价位能买到的安卓旗舰&#xff0c;要5G有5G、要高刷新…

设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动

以下内容转载于微信公众号&#xff1a;嵌入式企鹅圈。如有侵权&#xff0c;请告知删除。 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术。 对于初学者来说会非常困惑&#xff0c;甚至对Linux有一定基础的工程师而言…

写文章最难写的是标题

最近做事情有点沉不下心来&#xff0c;不知道是不是在家一个月养成的坏毛病还没改过来还是怎么回事。但仔细想了想&#xff0c;其实这只是个借口。自从高中以来&#xff0c;我这个毛病好像就有了&#xff0c;大概是高二的时候一直到现在&#xff0c;老是不能全心全意的静下心来…

对于局部变量_对于SQL常用查询优化方法的整理

查询进行优化&#xff0c;应尽量避免全表扫描&#xff0c;首先应考虑在where 及order by 涉及的列上建立索引:尝试下面的技巧以避免优化器错选了表扫描&#xff1a;使用ANALYZE TABLE tbl_name为扫描的表更新关键字分布。对扫描的表使用FORCE INDEX告知MySQL&#xff0c;相对于…

wampServer2.1错误(Could not execute menu item (internal error)

安装wampServer2.1后提示以下错误Could not execute menu item (internal error) [Exception] Could not perform service action 服务尚未启动错误原因&#xff1a;08端口被占用&#xff08;因为安装好wampServer后&#xff0c;默认的端口为80&#xff09;解决方法&#xff1a…

黄聪:如何使用CodeSmith批量生成代码(原创系列教程)

在上一篇我们已经用PowerDesigner创建好了需要的测试数据库,下面就可以开始用它完成批量代码生成的工作啦. 下面我会一步步的解释如何用CodeSmith实现预期的结果的,事先声明一下,在此只做一个简单的Demo,并不详细的讲解CodeSmith各个强大的功能,有兴趣的朋友可以打开CodeSmith的…

字符设备驱动基础2——用开发板来调试驱动的步骤

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 步骤1&#xff1a;获取编译后的内核源码与镜像 描述 该内核源码主要用来编译驱动源码。该内核源码必须与开发板运行的内核源码的版本一致&#xff0c;否则编译后的驱动程序在开发版上运行时&#xf…

c语音异或运算符_C语言中的按位异或运算符有什么用处?

原标题&#xff1a;C语言中的按位异或运算符有什么用处&#xff1f;想知道C语言中的按位异、运算符有什么用处&#xff0c;首先C语言中^为按位异或运算符&#xff0c;若两个二进制位相同&#xff0c;则结果为0&#xff0c;不同为1例&#xff1a;#include "stdio.h"ma…

Android 开发笔记 一

参考 : http://www.cnblogs.com/nightkidzxc/archive/2011/12/14/2379010.html 1.得到 SD 卡的目录 : String SDPATH Environment.getExternalStorageDriectory() "/"; 2.Activity 相当于 From Activity 以 Dialog形式显示在 Manifest中设置 : android:theme&qu…