二分查找
Akari观前提示:以下内容均为天王寺科技所属。与本人无任何联系。下集预告:十大排序——选择排序
参考网站:
代码随想录-二分查找
十大编程算法助程序员走上高手之路 | 菜鸟教程
704. 二分查找 - 力扣(LeetCode)
简介
在引入二分查找之前,先来想一个问题:在一个有序、无重复数组中 (想一想,为什么要求有序且无重复元素?),给一个目标值,要求定义一个函数返回此目标值在数组中的下标。
可能你脑海中第一印象是,遍历数组,依次比较目标值是否与每一个元素相等,相等就返回下标。
int search( int a[], int length, int target ) |
这种写法遍历每一个元素,太浪费时间,需要额外的内存,但易理解,那么使用二分不失为一种好方法:
二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,
- 如果中间元素正好是要查找的元素,则搜索过程结束;
- 如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。
- 如果在某一步骤数组 为空则代表找不到。
这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(log n) 。
限制:
- 数组元素必须有序
- 数组中不能有重复元素,必须保证返回值唯一
详解:
二分搜索也称为二分查找或折半查找,它充分利用了元素间的次序关系,采用分治策略,
可在最坏的情况下用 O(log n)完成搜索任务。它的基本思想是,将 n 个元素分成数量大致相同
的两部分,取 a[n/2]与欲查找的 x 作比较,如果 x==a[n/2]则找到 x,算法终止。如果 x<a[n/2],
则我们只要在数组 a 的左半部继续搜索 x(这里假设数组元素呈升序排列)。如果 x>a[n/2],
则我们只要在数组 a 的右半部继续搜索 x。
二分搜索过程可以描述为以下递归过程:
若待搜区间为空,返回-1;
否则
mid = (low+high)/2;
若 x 等于 a[mid],搜索成功,返回 mid;
若 x 小于 a[mid],在左半区间搜索;
若 x 大于 a[mid],在右半区间搜索;
写法
1、左闭右闭:
int search( int a[], int length, int target ){ //传入数组首地址、长度、待搜索目标值 |
2、左闭右开:
int search(int a[], int length, int target) |
要注意的问题
为什么分为左闭右闭和左闭右开?
我也不知道,反正就是这么规定的,记住就行了,其实也就是两种情况罢了。
每一种情况必须牢记到底是二分的哪种情况,是[ 左闭右闭 ],还是[ 左闭右开 ),不然程序你是看不懂的,更不要说写了。
区间的定义
- 左闭右闭时,为什么left<= right?左闭右开时,为什么left < right?
首先,target 所在的区间即为 left 和 right 之间。把它当成数学的区间看待,那么此区间必须是有意义的。
不论哪种情况,right最大所能取到的值都不能越界、区间都要有意义。
左闭右闭:
left <= right是有意义的,因为[left, right]是一个有效区间,可以取到。 - 左闭右开 以此类推。
边界条件
- **左闭右闭时,为什么target <= a[middle]时,right = middle - 1?而左闭右开却不是?**
还是区间是否有效的问题。
target < a[middle] 时,right = middle - 1:因为是闭区间[ ],右边界是可以取到的;而 < 说明target不在此区间,我们要更新查找的空间,即在此区间的左区间,即 middle - 1。如果是middle,那更新了个寂寞……
target > a[middle] 时,right = middle + 1:由上面分析可知,这次要更新的是右区间了,即middle + 1。 - 左闭右开
这种情况,是[ )了,右区间是取不到的,更新时就要注意了,动手在纸上画画吧!
好了,你已经学会二分了,快去敲代码试试吧!
C++版本
//左闭右闭 |
// 左闭右开 |