浅谈二分查找
相信我们都在编程过程中遇见查找问题,而查找的方式有许多种,我们最常见的、也是使用次数最多的便是二分查找了,原理简单且不容易超时。
二分查找的思想很容易理解,但大多数人都是通过记模板来使用,这篇博客将二分法做一个大概的总结,以供记忆和复习。
一、分享小故事
这里引用了CSDN中Charon_cc的一个很生动形象的例子:
有一天小明到图书馆借了 N 本书,出图书馆的时候,警报响了,于是保安把小明拦下,要检查一下哪本书没有登记出借。小明正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆…… 最终,检测了 logN 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是小明背着剩下的书走了。 从此,图书馆丢了 N - 1 本书。
多读两遍我们就会发现二分查找法的前提:
二、二分查找的前提
- 查找的目标只能有一个
- 查找的范围内元素是有序的(排序在C++里可以直接使用sort,而在C里可以使用冒泡排序等方法)
为什么是这样的一个前提呢?我们首先应该知道二分查找的原理:
三、二分查找的原理
在一个已经从小到大排好的数组里,先把目标与数组中间值比较
* 若目标>中间值,则接着找后半部分,前半部分舍弃。
* 若目标<中间值,则接着找前半部分,后半部分舍弃。
那有初学的朋友会问了:数组元素数是偶数的话怎么取中间值?
其实不必纠结这个问题,因为每次都丢掉数组的一半的话,这个问题是一定会出现的。
虽说叫二分查找,但并不是说我们必须严格的取一半,只是取一半时舍弃掉的不合要求的元素最多,比较节约时间而已。
而由于我们使用int类型,每次取的就是最中间两个数中靠左的那个,这样一来无非是在搜索的范围里多加一个数而已,只要我们继续进行二分查找并找好边界值,就永远不会有元素被落下。
四、二分查找的使用
这里只写我最常用的一种方式:[left,right]式
使用int函数进行运算:
int binarysearch(int arr[],int size,int target)
{
//size 可使用int size=sizeof(arr)/sizeof(arr[0])计算
int l=0,r=size-1; //l=left,r=right,m=middle
while(l<=r){
int m=l+(r-l)/2; //防止直接相加导致溢出
if(arr[m]>target){
r=m-1;
}
else if(arr[m]<target){
l=m+1;
}
else
return m;
}
return -1;
}
五、二分查找的性能
- 时间复杂度:O(1)~O(log2n)
- 空间复杂度:O(1)~O(log2n)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿刁!
评论