二分查找的各种情况实现以及一些注意点
2015-04-28 20:38
447 查看
转载请注明出处,谢谢:
http://blog.csdn.net/u014285517/article/details/45341741
说真的自己开始也认为二分查找实在太简单了,不屑一顾,可是上礼拜阿里实习面试真是教会我做人要踏实啊!上礼拜面试的事等下有时间再写一篇文章细谈,现在谈谈二分查找,建议大家先自己写写,然后再看下面的文章,效果更好。
让我们先看看一个朴素版的二分查找(其实也不算太朴素,不过因为这部分网上以及编程之美里都有详细描述以及代码实现,所以也就显得比较朴素了,注意事项会在代码注释里说明):
上面的代码还有什么问题呢?大家可以先想想,再往下看哈。
显然如果要查找的数在数组中存在着重复元素,而且我们还想返回该数的最小或最大下标,显然上面的程序是无法做到的,因为它一旦找到一个满足的就退出了。
下面我们来想想怎么解决这个问题。
最容易想到的办法就是在数组中找到某一个数后,直接不断循环减(加),来寻找满足条件的最小下标(最大下标)。相应代码如下:
现在可以想想上面的代码存在什么问题吗?
显然如果重复的元素过多,二分查找搞不好就直接退化成暴力查找了,所以显然这样是不可行的。大家可以自己先写写解决代码。
然后后看下面代码:
下面代码是找最大下标的:
下面我们再来思考两个类似问题,加深理解。
在一个非递减数组中(就是数组中存在相等的元素),求最小的下标i,使得a[i]
> t,存在返回下标i,不存在返回-1。
实现代码如下:
另一个类似问题:
在一个非递减数组中(就是数组中存在相等的元素),求最大的下标i,使得a[i]
< t,存在返回下标i,不存在返回-1。
实现代码如下:
如果把上面两个问题改成下面这样:
1.在一个非递减数组中(就是数组中存在相等的元素),求最**大**的下标i,使得a[i]
**>** t,存在返回下标i,不存在返回-1。
2.在一个非递减数组中(就是数组中存在相等的元素),求最**小**的下标i,使得a[i]
**<** t,存在返回下标i,不存在返回-1。
大家稍微想下应该能发现这种问题意义不大,我这里就不细说了。
注:上面代码都是自己写的,如果有bug欢迎指出。上面说的一些问题如果有错误也欢迎指出,谢谢。
补充java写的一个递归实现代码:
http://blog.csdn.net/u014285517/article/details/45341741
说真的自己开始也认为二分查找实在太简单了,不屑一顾,可是上礼拜阿里实习面试真是教会我做人要踏实啊!上礼拜面试的事等下有时间再写一篇文章细谈,现在谈谈二分查找,建议大家先自己写写,然后再看下面的文章,效果更好。
让我们先看看一个朴素版的二分查找(其实也不算太朴素,不过因为这部分网上以及编程之美里都有详细描述以及代码实现,所以也就显得比较朴素了,注意事项会在代码注释里说明):
<span style="font-size:18px;">/* 最朴素的二分查找:找数组a的下标s到下标e查找元素t */ #include<stdio.h> int binarySearch(int a[],int s,int e,int t) { int i = s,j = e,mid; while(i <= j) { /* (1)写成(i+j)/2,可能会导致求和中间结果的溢出,因为两个32位整数的和是有可能超过32位整数的范围的嘛 (2)因为四则运算符的优先级高于移位运算符>>,所以可以把mid = i+((j-i)>>1)简化下,不过注意不要写成mid = i+(j-i)>>1哈 (3)因为移位运算符比直接除快嘛,所以用>>1代替除2 */ mid = i+(j-i>>1);//(i+j)/2,写成这样可能会溢出 if(a[mid] == t) { return mid; } else { if(a[mid] > t) { j = mid-1; } else { i = mid+1; } } } return -1; } int main() { int a[10] = {1,3,5,6,7,8,9,12,13,14}; int t; if((t = binarySearch(a,0,9,7)) == -1) { printf("不存在\n"); } else { printf("存在,下标为%d\n",t); } } </span>
上面的代码还有什么问题呢?大家可以先想想,再往下看哈。
显然如果要查找的数在数组中存在着重复元素,而且我们还想返回该数的最小或最大下标,显然上面的程序是无法做到的,因为它一旦找到一个满足的就退出了。
下面我们来想想怎么解决这个问题。
最容易想到的办法就是在数组中找到某一个数后,直接不断循环减(加),来寻找满足条件的最小下标(最大下标)。相应代码如下:
<span style="font-size:18px;">#include<stdio.h> int binarySearch(int a[],int s,int e,int t) { int i = s,j = e,mid; while(i <= j) { mid = i+(j-i>>1); if(a[mid] == t) {//关键部分代码(查找数组中等于t的数的最小下标,最大下标同理) while(a[--mid] == t) { } return mid+1; } else { if(a[mid] > t) { j = mid-1; } else { i = mid+1; } } } return -1; } int main() { int a[10] = {1,3,5,9,9,9,9,12,13,14}; int t; if((t = binarySearch(a,0,9,9)) == -1) { printf("不存在\n"); } else { printf("存在,下标为%d\n",t); } } </span>
现在可以想想上面的代码存在什么问题吗?
显然如果重复的元素过多,二分查找搞不好就直接退化成暴力查找了,所以显然这样是不可行的。大家可以自己先写写解决代码。
然后后看下面代码:
<span style="font-size:18px;">#include<stdio.h> int binarySearch(int a[],int s,int e,int t) { int i = s,j = e,mid; while(i < j) { mid = i+(j-i>>1); if(a[mid] >= t) {//关键点:并不是等于就直接退出循环 j = mid; } else { i = mid+1; } } if(a[i] == t) { return i; } else { return -1; } } int main() { int a[10] = {1,3,9,9,9,9,9,9,13,14}; int t; if((t = binarySearch(a,0,9,9)) == -1) { printf("不存在\n"); } else { printf("存在,下标为%d\n",t); } } </span>
下面代码是找最大下标的:
<span style="font-size:18px;">/* 在一个非递减数组中(就是数组中存在相等的元素),用二分查找求 最大的下标i,使得a[i] = t,存在返回下标i,不存在返回-1 */ #include<stdio.h> int binarySearch(int a[],int s,int e,int t) { int i = s,j = e,mid; while(i < j) { mid = i+(j-i>>1); if(t >= a[mid]) {//关键点:并不是等于就直接退出循环 i = mid i = mid; } else { j = mid-1; } } if(a[i] == t) { return i; } else { return -1; } } int main() { int a[10] = {1,9,9,9,9,9,9,12,13,14}; int t; if((t = binarySearch(a,0,9,9)) == -1) { printf("不存在\n"); } else { printf("存在,下标为%d\n",t); } } </span>
下面我们再来思考两个类似问题,加深理解。
在一个非递减数组中(就是数组中存在相等的元素),求最小的下标i,使得a[i]
> t,存在返回下标i,不存在返回-1。
实现代码如下:
<span style="font-size:18px;">/* 在一个非递减数组中(就是数组中存在相等的元素),用二分查找求 最小的下标i,使得a[i] > t,存在返回下标i,不存在返回-1 */ #include<stdio.h> int binarySearch(int a[],int s,int e,int t) { int i = s,j = e,mid; while(i < j) { mid = i+(j-i>>1); if(t >= a[mid]) { i = mid+1; } else { j = mid; } } if(a[i] > t) { return i; } else { return -1; } } int main() { int a[10] = {1,9,9,9,9,9,9,12,13,14}; int t; if((t = binarySearch(a,0,9,8)) == -1) { printf("不存在\n"); } else { printf("存在,下标为%d\n",t); } } </span>
另一个类似问题:
在一个非递减数组中(就是数组中存在相等的元素),求最大的下标i,使得a[i]
< t,存在返回下标i,不存在返回-1。
实现代码如下:
<span style="font-size:18px;">/* 在一个非递减数组中(就是数组中存在相等的元素),用二分查找求 最大的下标i,使得a[i] < t,存在返回下标i,不存在返回-1 */ #include<stdio.h> int binarySearch(int a[],int s,int e,int t) { int i = s,j = e,mid; //避免出现t比s~e区间内所有元素都大时,跳不出循环的bug if(a[j] < t) { return j; } while(i < j) { mid = i+(j-i>>1); if(t <= a[mid]) { j = mid-1; } else { i = mid; } } if(a[i] < t) { return i; } else { return -1; } } int main() { int a[10] = {1,9,9,9,9,9,9,12,13,14}; int t; if((t = binarySearch(a,0,9,10)) == -1) { printf("不存在\n"); } else { printf("存在,下标为%d\n",t); } } </span>
如果把上面两个问题改成下面这样:
1.在一个非递减数组中(就是数组中存在相等的元素),求最**大**的下标i,使得a[i]
**>** t,存在返回下标i,不存在返回-1。
2.在一个非递减数组中(就是数组中存在相等的元素),求最**小**的下标i,使得a[i]
**<** t,存在返回下标i,不存在返回-1。
大家稍微想下应该能发现这种问题意义不大,我这里就不细说了。
注:上面代码都是自己写的,如果有bug欢迎指出。上面说的一些问题如果有错误也欢迎指出,谢谢。
补充java写的一个递归实现代码:
//递归实现 public void <span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">binarySearch</span>(int[] a, int x, int beginIndex, int endIndex) { int len = endIndex - beginIndex + 1; if (endIndex < beginIndex) {//防止进入无限递归 System.out.println("not find"); return; } if (a[beginIndex + len / 2] == x) { System.out.println("find index is:" + (beginIndex + len / 2)); return; } else { if (x > a[beginIndex + len / 2]) { <span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">binarySearch</span>(a, x, beginIndex + len / 2 + 1, endIndex); } else { <span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">binarySearch</span>(a, x, beginIndex, beginIndex + len / 2 - 1); } } }
相关文章推荐
- 二分查找需要注意的问题,以及在数据库内核中的实现
- 二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现[谁有源码麻烦贴过来个链接学习学习]
- 二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现
- 二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现
- 二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现
- 跑马灯各种实现的方法,以及效果,注意事项
- 二分查找的实现及注意事项
- [置顶] 二分查找各种情况大总结
- 二分搜索树的实现以及各种操作(支持重复节点)
- 二分查找各种情况大总结
- 二分查找,二叉查找树(二叉排序树)的基本思想以及算法实现
- SBTree的左旋右旋以及各种调整操作的基本实现(包含查找第k大的数值)
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
- 数据结构C#实现-二叉查找树的创建,查找,以及各种递归(非递归)遍历算法
- 【Cuda并行编程之一】二分查找的探究以及Cuda的简单实现&&相关面试题介绍
- 用java实现的一些插入(顺序和乱序)和查找(顺序和二分)
- 二分查找各种情况大总结
- 【Cuda并行编程之一】二分查找的探究以及Cuda的简单实现&&相关面试题介绍
- C语言实现直接插入排序,冒泡排序以及二分查找(巩固理解记忆)
- 二分查找的一些注意事项