折半查找(即二分查找)
二分搜索算法:给定排好序的n个元素arr[0:n-1],在这n个元素中找出一特定元素x.
首先比较容易想到的办法是用顺序搜索方法,逐个比较a[0:n-1]中的元素 ,直至找出元素x或搜索遍整个数组后确定x不在其中,这个方法没有很好的利用n个元素已排好序这个条件,因此在最坏情况下,顺序搜索的方法需要O(n)次比较。
而二分搜素搜的基本思想是将n个元素分成个数大致相同的两半,取arr[n/2]与x进行比较,如果x=arr[n/2],则找到x,算法终止。如果x<arr[n/2],则只要在数组arr的左半部继续搜索x。如果x>arr[n/2],则只要在数组arr的右半部继续搜索x。最坏情况下,也只需O(logn)次比较。
二分搜索算法:给定排好序的n个元素arr[0:n-1],在这n个元素中找出一特定元素x.
首先比较容易想到的办法是用顺序搜索方法,逐个比较a[0:n-1]中的元素 ,直至找出元素x或搜索遍整个数组后确定x不在其中,这个方法没有很好的利用n个元素已排好序这个条件,因此在最坏情况下,顺序搜索的方法需要O(n)次比较。
而二分搜素搜的基本思想是将n个元素分成个数大致相同的两半,取arr[n/2]与x进行比较,如果x=arr[n/2],则找到x,算法终止。如果x<arr[n/2],则只要在数组arr的左半部继续搜索x。如果x>arr[n/2],则只要在数组arr的右半部继续搜索x。最坏情况下,也只需O(logn)次比较。
众所周知,二分查找是非常重要的查找方法,无论是笔试还是面试的过程中,都是如此,下面让我们一起来研究一下二分查找算法中的难点和考点。
1,溢出问题(迭代实现)
//代码1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int bin_search(int arr[],int key,int sz)
{
int i=0;
int left=0;
<span style="color:#ff0000;">int right=sz-1</span>;
while(<span style="color:#ff0000;">left<=right</span>)
{
<span style="color:#ff0000;">int mid=(left+right)/2;</span> //如果left和right都很大,则mid将产生溢出,导致错误
if(key==arr[mid])
{
return mid;
}
else if(key<arr[mid])
{
<span style="color:#ff0000;">right=mid-1</span>;
}
else
{
left=mid+1;
}
}
<span style="color:#ff0000;"> return -1</span>;
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int key=5;
int sz=sizeof(arr)/sizeof(arr[0]);
int ret=bin_search(arr,key,sz);
if(ret==-1)
{
printf("没找到所查找元素\n");
}
else
{
printf("所查找元素的下标为:%d\n",ret);
}
system("pause");
return 0;
}
注意:红色标注的都是最喜欢考到的地方
正如代码中注释的那样,
//如果left和right都很大,则mid将产生溢出,导致错误这样的话,我们就不得不想出一个办法解决溢出问题,可以联系一下日常的爬楼梯。
除了以上两种方法,还能不能有其他防止溢出的方法呢,
第一种最简单,但是存在风险,第二种就比较常用了,第三种一般想不到,所以建议学会理解第二种防止溢出的办法。
//如果left和right都很大,则mid将产生溢出,导致错误这样的话,我们就不得不想出一个办法解决溢出问题,可以联系一下日常的爬楼梯。
//代码2:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int bin_search(int arr[],int key,int sz)
{
int i=0;
int left=0;
int right=sz-1;
while(left<=right)
{
int mid=(right-left)/2+left; //防止数据发生溢出
if(key==arr[mid])
{
return mid;
}
else if(key<arr[mid])
{
right=mid-1;
}
else
{
left=mid+1;
}
}
return -1;
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int key=5;
int sz=sizeof(arr)/sizeof(arr[0]);
int ret=bin_search(arr,key,sz);
if(ret==-1)
{
printf("没找到所查找元素\n");
}
else
{
printf("所查找元素的下标为:%d\n",ret);
}
system("pause");
return 0;
}
除了以上两种方法,还能不能有其他防止溢出的方法呢,
//代码3:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int bin_search(int arr[],int key,int sz)
{
int i=0;
int left=0;
int right=sz-1;
while(left<=right)
{
int mid=(left&right)+((left^right)>>1); //防止数据发生溢出
if(key==arr[mid])
{
return mid;
}
else if(key<arr[mid])
{
right=mid-1;
}
else
{
left=mid+1;
}
}
return -1;
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int key=1;
int sz=sizeof(arr)/sizeof(arr[0]);
int ret=bin_search(arr,key,sz);
if(ret==-1)
{
printf("没找到所查找元素\n");
}
else
{
printf("所查找元素的下标为:%d\n",ret);
}
system("pause");
return 0;
}
第一种最简单,但是存在风险,第二种就比较常用了,第三种一般想不到,所以建议学会理解第二种防止溢出的办法。
2,区间问题
如果仔细观察,你就会发现上面几个代码用的都是前闭后闭区间,因为right是从sz-1开始取值的,那么如果是前闭后开区间,代码又会发生怎样的变化呢?让我们拭目以待。
<pre name="code" class="cpp">#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int bin_search(int arr[],int key,int sz)
{
int i=0;
int left=0;
<span style="color:#ff0000;">int right=sz;</span>
while(<span style="color:#ff0000;">left<right</span>)
{
int mid=(left&right)+((left^right)>>1); //防止数据发生溢出
if(key==arr[mid])
{
return mid;
}
else if(key<arr[mid])
{
<span style="color:#ff0000;"> right=mid;</span>
}
else
{
left=mid+1;
}
}
return -1;
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int key=8;
int sz=sizeof(arr)/sizeof(arr[0]);
int ret=bin_search(arr,key,sz);
if(ret==-1)
{
printf("没找到所查找元素\n");
}
else
{
printf("所查找元素的下标为:%d\n",ret);
}
system("pause");
return 0;
}
注意:红色标注是改变的地方
3,递归实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int bin_search(int arr[],int left,int right,int key)
{
while(left<right)
{
int mid=(left&right)+((left^right)>>1); //防止数据发生溢出
if(key==arr[mid])
{
return mid;
}
else if(key<arr[mid])
{
return bin_search(arr,left,mid,key);
}
else
{
return bin_search(arr,mid+1,right,key);
}
}
return -1;
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9};
int key=9;
int sz=sizeof(arr)/sizeof(arr[0]);
int ret=bin_search(arr,0,sz,key);
if(ret==-1)
{
printf("没找到所查找元素\n");
}
else
{
printf("所查找元素的下标为:%d\n",ret);
}
system("pause");
return 0;
}