二分查找的注意事项

 

二分查找的各种情况实现以及一些注意点

标签: 二分查找编程之美面试详细解答算法
  539人阅读  评论(2)  收藏  举报
  分类:

转载请注明出处,谢谢:

http://blog.csdn.NET/u014285517/article/details/45341741


说真的自己开始也认为二分查找实在太简单了,不屑一顾,可是上礼拜阿里实习面试真是教会我做人要踏实啊!上礼拜面试的事等下有时间再写一篇文章细谈,现在谈谈二分查找,建议大家先自己写写,然后再看下面的文章,效果更好。

  让我们先看看一个朴素版的二分查找(其实也不算太朴素,不过因为这部分网上以及编程之美里都有详细描述以及代码实现,所以也就显得比较朴素了,注意事项会在代码注释里说明): 

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2. 最朴素的二分查找:找数组a的下标s到下标e查找元素t  
  3. */  
  4. #include<stdio.h>  
  5.   
  6. int binarySearch(int a[],int s,int e,int t) {  
  7.     int i = s,j = e,mid;  
  8.     while(i <= j) {  
  9.      /*  
  10.     (1)写成(i+j)/2,可能会导致求和中间结果的溢出,因为两个32位整数的和是有可能超过32位整数的范围的嘛  
  11.     (2)因为四则运算符的优先级高于移位运算符>>,所以可以把mid = i+((j-i)>>1)简化下,不过注意不要写成mid = i+(j-i)>>1哈  
  12.     (3)因为移位运算符比直接除快嘛,所以用>>1代替除2  
  13.     */  
  14.         mid = i+(j-i>>1);//(i+j)/2,写成这样可能会溢出   
  15.         if(a[mid] == t) {  
  16.             return mid;  
  17.         } else {  
  18.             if(a[mid] > t) {  
  19.                 j = mid-1;  
  20.             } else {  
  21.                 i = mid+1;  
  22.             }  
  23.         }  
  24.     }  
  25.     return -1;        
  26. }  
  27.   
  28. int main() {  
  29.     int a[10] = {1,3,5,6,7,8,9,12,13,14};  
  30.     int t;  
  31.     if((t = binarySearch(a,0,9,7)) == -1) {  
  32.         printf("不存在\n");  
  33.     } else {  
  34.         printf("存在,下标为%d\n",t);  
  35.     }  
  36. }  

上面的代码还有什么问题呢?大家可以先想想,再往下看哈。


显然如果要查找的数在数组中存在着重复元素,而且我们还想返回该数的最小或最大下标,显然上面的程序是无法做到的,因为它一旦找到一个满足的就退出了。

下面我们来想想怎么解决这个问题。 最容易想到的办法就是在数组中找到某一个数后,直接不断循环减(加),来寻找满足条件的最小下标(最大下标)。相应代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include<stdio.h>  
  2.   
  3. int binarySearch(int a[],int s,int e,int t) {  
  4.     int i = s,j = e,mid;  
  5.     while(i <= j) {  
  6.         mid = i+(j-i>>1);  
  7.         if(a[mid] == t) {//关键部分代码(查找数组中等于t的数的最小下标,最大下标同理)  
  8.             while(a[--mid] == t) {  
  9.                   
  10.             }  
  11.             return mid+1;  
  12.         } else {  
  13.             if(a[mid] > t) {  
  14.                 j = mid-1;  
  15.             } else {  
  16.                 i = mid+1;  
  17.             }  
  18.         }  
  19.     }  
  20.     return -1;        
  21. }  
  22.   
  23. int main() {  
  24.     int a[10] = {1,3,5,9,9,9,9,12,13,14};  
  25.     int t;  
  26.     if((t = binarySearch(a,0,9,9)) == -1) {  
  27.         printf("不存在\n");  
  28.     } else {  
  29.         printf("存在,下标为%d\n",t);  
  30.     }  
  31. }  

现在可以想想上面的代码存在什么问题吗?


显然如果重复的元素过多,二分查找搞不好就直接退化成暴力查找了,所以是不太好的。大家可以自己先写写解决代码。

然后后看下面代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include<stdio.h>  
  2.   
  3. int binarySearch(int a[],int s,int e,int t) {  
  4.     int i = s,j = e,mid;  
  5.     while(i < j) {  
  6.         mid = i+(j-i>>1);  
  7.         if(a[mid] >= t) {//关键点:并不是等于就直接退出循环  
  8.             j = mid;  
  9.         } else {  
  10.             i = mid+1;  
  11.         }  
  12.     }  
  13.     if(a[i] == t) {  
  14.         return i;   
  15.     } else {  
  16.         return -1;    
  17.     }         
  18. }  
  19.   
  20. int main() {  
  21.     int a[10] = {1,3,9,9,9,9,9,9,13,14};  
  22.     int t;  
  23.     if((t = binarySearch(a,0,9,9)) == -1) {  
  24.         printf("不存在\n");  
  25.     } else {  
  26.         printf("存在,下标为%d\n",t);  
  27.     }  
  28. }  

下面代码是找最大下标的:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2. 在一个非递减数组中(就是数组中存在相等的元素),用二分查找求 
  3. 最大的下标i,使得a[i] = t,存在返回下标i,不存在返回-1  
  4. */   
  5. #include<stdio.h>  
  6.   
  7. int binarySearch(int a[],int s,int e,int t) {  
  8.     int i = s,j = e,mid;  
  9.     while(i < j) {  
  10.         mid = i+(j-i+1>>1);  
  11.         if(t >= a[mid]) {//关键点:并不是等于就直接退出循环 i = mid  
  12.             i = mid;  
  13.         } else {  
  14.             j = mid-1;  
  15.         }  
  16.     }  
  17.     if(a[i] == t) {  
  18.         return i;   
  19.     } else {  
  20.         return -1;    
  21.     }         
  22. }  
  23.   
  24. int main() {  
  25.     int a[10] = {1,9,9,9,9,9,9,12,13,14};  
  26.     int t;  
  27.     if((t = binarySearch(a,0,9,9)) == -1) {  
  28.         printf("不存在\n");  
  29.     } else {  
  30.         printf("存在,下标为%d\n",t);  
  31.     }  
  32. }  

下面我们再来思考两个类似问题,加深理解。

在一个非递减数组中(就是数组中可能存在相等的元素),求最小的下标i,使得a[i] > t,存在返回下标i,不存在返回-1。 

实现代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2. 在一个非递减数组中(就是数组中存在相等的元素),用二分查找求 
  3. 最小的下标i,使得a[i] > t,存在返回下标i,不存在返回-1  
  4. */   
  5. #include<stdio.h>  
  6.   
  7. int binarySearch(int a[],int s,int e,int t) {  
  8.     int i = s,j = e,mid;  
  9.     while(i < j) {  
  10.         mid = i+(j-i>>1);  
  11.         if(t >= a[mid]) {  
  12.             i = mid+1;  
  13.         } else {  
  14.             j = mid;  
  15.         }  
  16.     }  
  17.     if(a[i] > t) {  
  18.         return i;   
  19.     } else {  
  20.         return -1;    
  21.     }         
  22. }  
  23.   
  24. int main() {  
  25.     int a[10] = {1,9,9,9,9,9,9,12,13,14};  
  26.     int t;  
  27.     if((t = binarySearch(a,0,9,8)) == -1) {  
  28.         printf("不存在\n");  
  29.     } else {  
  30.         printf("存在,下标为%d\n",t);  
  31.     }  
  32. }   

另一个类似问题:

在一个非递减数组中(就是数组中可能存在相等的元素),求最大的下标i,使得a[i] < t,存在返回下标i,不存在返回-1。 

实现代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2. 在一个非递减数组中(就是数组中存在相等的元素),用二分查找求 
  3. 最大的下标i,使得a[i] < t,存在返回下标i,不存在返回-1  
  4. */   
  5. #include<stdio.h>  
  6.   
  7. int binarySearch(int a[],int s,int e,int t) {  
  8.     int i = s,j = e,mid;  
  9.     while(i < j) {  
  10.         mid = i+(j-i+1>>1);//j-i>>1改成了j-i+1>>1,避免出现t比s~e区间内所有元素都大时,跳不出循环的bug<span style="font-family: Arial, Helvetica, sans-serif;">  
  11. </span>     if(t <= a[mid]) {  
  12.             j = mid-1;  
  13.         } else {  
  14.             i = mid;  
  15.         }  
  16.     }  
  17.     if(a[i] < t) {  
  18.         return i;   
  19.     } else {  
  20.         return -1;    
  21.     }         
  22. }  
  23.   
  24. int main() {  
  25.     int a[10] = {1,9,9,9,9,9,9,12,13,14};  
  26.     int t;  
  27.     if((t = binarySearch(a,0,9,10)) == -1) {  
  28.         printf("不存在\n");  
  29.     } else {  
  30.         printf("存在,下标为%d\n",t);  
  31.     }  
  32. }  

如果把上面两个问题改成下面这样: 

1.在一个非递减数组中(就是数组中存在相等的元素),求最**大**的下标i,使得a[i] **>** t,存在返回下标i,不存在返回-1。 

2.在一个非递减数组中(就是数组中存在相等的元素),求最**小**的下标i,使得a[i] **<** t,存在返回下标i,不存在返回-1。 

大家稍微想下应该能发现这种问题意义不大,我这里就不细说了。 


注:上面代码都是自己写的,如果有bug欢迎指出。上面说的一些问题如果有错误也欢迎指出,谢谢。


补充Java写的一个递归实现代码:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //递归实现  
  2. public void binarySearch(int[] a, int x, int beginIndex, int endIndex) {  
  3.     int len = endIndex - beginIndex + 1;  
  4.     if (endIndex < beginIndex) {//防止进入无限递归  
  5.         System.out.println("not find");  
  6.         return;  
  7.     }  
  8.     if (a[beginIndex + len / 2] == x) {  
  9.         System.out.println("find index is:" + (beginIndex + len / 2));  
  10.         return;  
  11.     } else {  
  12.         if (x > a[beginIndex + len / 2]) {  
  13.             binarySearch(a, x, beginIndex + len / 2 + 1, endIndex);  
  14.         } else {  
  15.             binarySearch(a, x, beginIndex, beginIndex + len / 2 - 1);  
  16.         }  
  17.     }  
  18. }  


安装Docker安装插件,可以按照以下步骤进行操作: 1. 首先,安装Docker。可以按照官方文档提供的步骤进行安装,或者使用适合您操作系统的包管理器进行安装。 2. 安装Docker Compose插件。可以使用以下方法安装: 2.1 下载指定版本的docker-compose文件: curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2.2 赋予docker-compose文件执行权限: chmod +x /usr/local/bin/docker-compose 2.3 验证安装是否成功: docker-compose --version 3. 在安装插件之前,可以测试端口是否已被占用,以避免编排过程中出错。可以使用以下命令安装netstat并查看端口号是否被占用: yum -y install net-tools netstat -npl | grep 3306 现在,您已经安装Docker安装Docker Compose插件,可以继续进行其他操作,例如上传docker-compose.yml文件到服务器,并在服务器上安装MySQL容器。可以参考Docker的官方文档或其他资源来了解如何使用DockerDocker Compose进行容器的安装和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Docker安装docker-compose插件](https://blog.youkuaiyun.com/qq_50661854/article/details/124453329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Docker安装MySQL docker安装mysql 完整详细教程](https://blog.youkuaiyun.com/qq_40739917/article/details/130891879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值