二分查找的多种实现

来源:互联网 发布:adc0804 51单片机 编辑:程序博客网 时间:2024/06/05 03:11
 折半查找(即二分查找)

二分搜索算法:给定排好序的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将产生溢出,导致错误这样的话,我们就不得不想出一个办法解决溢出问题,可以联系一下日常的爬楼梯。

//代码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;} 




1 0
原创粉丝点击