折半查找法.docx
《折半查找法.docx》由会员分享,可在线阅读,更多相关《折半查找法.docx(13页珍藏版)》请在冰豆网上搜索。
折半查找法
二分查找是在我们整个数据结构当中一个比较重要的算法,它的思想在我们的实际开发过程当中应用得非常广泛。
在实际应用中,有些数据序列是已经经过排序的,或者可以将数据进行排序,排序后的数据我们可以通过某种高效的查找方式来进行查找,今天要讲的就是折半查找法(二分查找),
它的时间复杂度为O(logn),将以下几个方面进行概述
了解二分查找的原理与思想
分析二分查找的时间复杂度
掌握二分查找的实现方法
了解二分查找的使用条件和场景
1二分查找的原理与思想
在上一个章节当中,我们学习了各种各样的排序的算法,接下来我们就讲解一下针对有序集合的查找的算法—二分查找(BinarySearch、折半查找)算法,二分查找呢,是一种非常容易懂的查找算法,它的思想在我们的生活中随处可见,
比如说:
同学聚会的时候喜欢玩一个游戏——猜数字游戏,比如在1-100以内的数字,让别人来猜从,猜的过程当中会被提示是猜大了还是猜小了,直到猜中为止。
这个过程其实就是二分查找的思想的体现,这是个生活中的例子,在我们现实开发过程当中也有很多应用到二分查找思想的场景。
比如说仙现在有10个订单,它的金额分别是6、12、15、19、24、26、29、35、46、67请从中找出订单金额为15的订单,利用二分查找的思想,那我们每一次都会与中间的数据进行比较来缩小我们查找的范围,下面这幅图代表了查找的过程,其中low,high代表了待查找的区间的下标范围,mid表示待查找区间中间元素的下标(如果范围区间是偶数个导致中间的数有两个就选择较小的那个)
第一次二分查找
第二次二分查找
第三次二分查找
通过这个查找过程我们可以对二分查找的思想做一个汇总:
二分查找针对的是一个有序的数据集合,查找思想有点类似于分治思想。
每次都通过跟区间的中间元素对比,将待查找的区间范围缩小为原来的一半,直到找到要查找的元素,或者区间被缩小为0。
一:
查找的数据有序
二:
每次查找,数据的范围都在缩小,直到找到或找不到为止。
2二分查找的时间复杂度
我们假设数据大小为n,每次查询完之后,数据就缩减为原来的一半,直到最后的数据大小被缩减为1
n,n/2,n/4,n/8,n/16,n/32,…………,1
这是一个等比数列,当数据大小变为1时,
k是总共缩小的次数,而每次缩小只涉及两个数据的比较大小,所以经过了K次区间缩小操作,通过计算k的值我们就可以得出二分查找的时间复杂度是O(logn)
这是一种非常高效的时间复杂度,有时候甚至比O
(1)复杂度更高效,为什么这么说呢?
因为对于logn来说即使n的非常大,对应的logn的值也会很小,之前在学习O
(1)时间复杂度时我们说过O
(1)代表的是一种常量级的时间复杂度,并不是说代码只需要执行一条语句,有时候可能要执行100次,1000次,这样常规级次数都用O
(1)来表示,所以,常量级时间复杂度的算法有时候还没有O(logn)的算法执行效率高。
3二分查找算法的实现
I有序数列当中不存在重复的元素
#include
usingnamespacestd;
/*
但是若low+high>Interger.MAX_VALUE时,此时会导致数据溢出,则导致mid错误,
所以mid应该改为low+(high-low)/2;
*/
//递归二分查找//
intbinaS(int*arr,intkey,inthigh,intlow)
{
if(low>high)
return-1;
intmid=(high+low)/2;
if(arr[mid]==key)
{
returnmid;
}
elseif(arr[mid]>key)
{
binaS(arr,key,low,mid-1);
}
else
{
binaS(arr,key,mid+1,high);
}
}
intmain()
{
//二分查找
inta[4]={11,22,33,44};
intkey;
cin>>key;
cout<//intlow=0,high=3,flag=1,mid;
//while(low<=high)
//{
//mid=(low+high)/2;
//if(key==a[mid])
//{
//cout<//
////flag=0;
////break;
//}
//elseif(key//{
//high=mid-1;
//}
//elseif(key>a[mid])
//{
//low=low+1;
//}
//}
//if(flag)
//cout<<"没有找到";
return0;
}
II有序数列当中存在重复的元素
思路1:
#include
usingnamespacestd;
//数据序列中第一个等于给定的元素(重复元素)
intbinarySearch(int*array,intvalue,intlength)
{
intlow=0;
inthigh=length-1;
while(low<=high)
{
intmid=low+(high-low)/2;
if(array[mid]==value)
{
//当我们的mid指针已经指向第一个元素或者我们的mid指针前一个元素不等于我们的查找
//元素的时候,直接返回mid下标
if(mid==0||array[mid-1]!
=value)
{
returnmid;
}//否则,继续二分查找
else
{
high=mid-1;
}
}
elseif(array[mid]{
low=mid+1;
}
elseif(array[mid]>value)
{
high=mid-1;
}
}
return-1;
}
intmain()
{
intarray[]={6,12,15,19,24,26,29,29,29,67};
cout<return0;
}
思路2:
#include
usingnamespacestd;
/*
需求2:
从数据序列中查找最后一个值等于给定值的元素
*/
intbinarySearch(int*arr,intvalue,intlen)
{
intlow=0,high=len-1;
while(low<=high)
{
intmid=low+(high-low)/2;
if(arr[mid]==value)
{
//和查找第一个元素的思路是一样的
if(mid==len-1||arr[mid+1]!
=value)
returnmid;
//否则继续查找,往后查找
else
{
low=mid+1;
}
}
elseif(arr[mid]>value)
{
high=mid-1;
}
elseif(arr[mid]{
low=mid+1;
}
}
return-1;
}
intmain()
{
intarray[]={6,12,15,19,24,26,29,29,29,67};
cout<return0;
}
#include
usingnamespacestd;
/*
从数据序列中查找第一个大于等于给定值的元素
while(low<=high)
{
intmid=low+(high-low)/2;
if(arr[mid]>=value)
{
if(mid==0||arr[mid-1]returnmid;
else
high=mid-1;
}
elseif(arr[mid]{
low=mid+1;
}
}
return-1;
*/
intbinarySearch(int*arr,intvalue,intlen)
{
intlow=0,high=len-1,max=-1;
while(low<=high)
{
intmid=low+(high-low)/2;
if(arr[mid]==value)
{
if(mid==0||arr[mid-1]!
=value)
{
returnmid;
}
else
{
high=mid-1;
}
}
elseif(arr[mid]>value)
{
max=mid;
high=mid-1;
}
elseif(arr[mid]{
low=mid+1;
}
}
returnmax;
}
intmain()
{
intarray[]={6,12,15,19,24,26,29,29,29,67};//{1,3,5,7,9};
cout<return0;
}
#include
usingnamespacestd;
/*
从数据序列当中查找出最后一个小于等于给定值的元素
*/
intbinarySearch(int*arr,intvalue,intlen)
{
intlow=0,higg=len-1;
while(low<=high)
{
intmid=low+(high-low)>>1;
if(arr[mid]<=value)//1122
{
if(mid==len-1||arr[mid+1]>value)
returnmid;
else
low=mid+1;
}
else
{
high=mid-1;
}
}
return-1;
}
intmain()
{
return0;
}
二分查找法的使用条件和场景
拓展:
log2NO(logN)logaN=logcN/logca,因1/logca不是1,所以舍去,剩下logcN,c可以是任何的值,不关心,所以是logN
案例一:
跳房子(这…,看题我都要看半小时)
每年,奶牛都会举办一场特殊版本的跳房子活动,其中包括小心翼翼地从河中的一块石头跳到另一块石头。
这个令人兴奋的活动发生在一条又长又直的河流上,一块石头开始,另一块石头结束。
从开始走的长度L(1<=L<=1,000,000,000)。
从开始到结束之间的石头数量为N(0<=N<=50000),从开始每块石头有一个整数距离di(0