二分查找是很基础的一种算法
例题:
在一个有序数组中查找具体的某个数,如果找到了返回,这个数的下标。找不到的返回-1
其原理图如图所示
因为是有序的数列,所以可以将要查找的数与中间的数进行比较,如果要查找的数比中间的数大,那么他就在中间数的右边,反之,就在中间数的左边
例如上图,设上图序列为数组a
中间的数为a[0]+a[9]/2,即5
如果要查找的数比5大,那么缩小范围,对5右边的数在进行二分,此时的范围是
a[6]~a[9]之间,右边的数(a[9])不变,左边的数变为a[5+1]
如果要查找的数比5小,那么就缩小范围,对5左边的数进行二分,此时的范围是a[0]~a[4]
左边的数a[0]不变,右边的数变为a[5-1],将这个思路广泛化,得到关键代码如下:
//根据索引确定中间的数,在让中间的数arr[mid],与left或者right进行比较 //left,right,mid计算的都是下标,因为返回的值需要为下标 //而进行比较的值是arr[mid],即中间下标对应的值 int binary_search(int arr[],int k,int sz)//sz表示这个数组的长度 { int left,right; left=0; right=sz-1;//最右边的数的下标是数组长度-1,例如数组长度是10,那么最右边数的下标就是a[9] while(left<=right)//如果left大于right,表示找不到该数 { int mid=(left+right)/2;//中间的数的下标 if(k<arr[mid]) right=mid-1; else if(k>arr[mid]) left=mid+1; else return mid; } return -1; }
那么最终代码如下:
#include<stdio.h> int binary_search(int arr[],int k,int sz) { int left,right; left=0; right=sz-1; while(left<=right) { int mid=(left+right)/2; if(k<arr[mid]) right=mid-1; else if(k>arr[mid]) left=mid+1; else return mid; } return -1; } int main() { int arr[]={1,2,3,4,5,6,7,8,9,10}; int k=7; int sz=sizeof(arr)/sizeof(arr[0]); int ret=binary_search(arr,k,sz); if(ret==-1) printf("找不到指定的数字\n"); else printf("%d",ret); return 0; }
注意事项:非常关键
1.mid不能写在while循环的外面
int binary_search(int arr[],int k,int sz) { int left,right; left=0; right=sz-1; int mid=(left+right)/2; while(left<=right) { if(k<arr[mid]) right=mid-1; else if(k>arr[mid]) left=mid+1; else return mid; } return -1; }
因为mid的值会根据left和right值的改变而改变了,如果mid值不变,就不能进行范围的缩小,只能进行一次二分查找,得不到最终结果
2.left<=right不能少了=
int binary_search(int arr[],int k,int sz) { int left,right; left=0; right=sz-1; while(left<right) { int mid=(left+right)/2; if(k<arr[mid]) right=mid-1; else if(k>arr[mid]) left=mid+1; else return mid; } return -1; }
如果left和right同时指向这一元素,而这一元素正好是我们需要查找的元素,写为left<right的话,那么就会跳过我们需要查找的元素,返回-1
3.binary_search函数不能写为如下形式
int binary_search(int arr[],int k) { int left,right; left=0; sz=sizeof(arr)/sizeof(arr[0]); right=sz-1; while(left<=right) { int mid=(left+right)/2; if(k<arr[mid]) right=mid-1; else if(k>arr[mid]) left=mid+1; else return mid; } return -1; }
即,在该函数内计算数组的大小
因为数组在传参的时候,只会传递数组的第一个元素的地址,int arr[]是指针类型的参数,即int *arr,所以对于sizeof(arr)是一个地址的大小,即4,而arr[0]是int类型元素,其大小也为4
所以这里的sz=1/1=1,得不到最终的结果,这一点千万注意。