对于一个有序的数据序列,我们在查找其中的某一个数时,除了通过遍历的方式查找外,还可以利用二分查找来有效提高我们的查找效率。那么二分查找的原理是什么?这么实现呢?跟着我继续往下看吧!
众所周知,查找是通过将拿到的数据与自己想要查找数据进行对比的一个过程,如果相同则查找成功,反之则“淘汰”当前数据,继续查找。所以查找也可以看作是一个淘汰非查找目标数据的过程,所以每次查找能够淘汰的数据的多少也就一定程度上反映了查找方法的优越性,普通的遍历每次能够淘汰一个数据,而二分查找每次就可以淘汰一半的数据,效率可以说是相当不错了,接下来我们就一起来实现它吧!
首先来了解二分查找的原理。
二分查找过程如下:
例如我们拿到了一个如下有序序列:1,2,3,4,5,6,7,8,9,10;
假设我们要查找数据7,
首先我们会进行比较序列最中间的值5,发现5<7,因为序列是升序,5的左边都比5小,自然也比7小,所以直接淘汰5以及它左边的所有数据,然后进行比较右边最中间的数据8,发现8>7,淘汰8以及右边的所有数据,然后与7比较查找成功。
要实现以上过程,首先我们需要两个变量作为标志限制我们每次查找的范围和一个变量作为搜索标志指向查找范围的中间的数据,代码实现如下:
int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int left = 0; int right = sizeof(arr)/sizeof(arr[0])-1;//数组下标从0开始,所以需要减一 mid = (left + right) / 2;
因为每一次非成功查找,都需要淘汰一半的数据,如果对比中间值比查找值大,则说明查找值在中间值左边,right=mid-1右标志左移;如果对比中间值比查找值小,则说明查找值在中间值右边,left=mid+1左标志右移。可以发现,每次范围改变,mid的值也应该跟着更新,所以需要把mid的赋值放到循环中。
循环结束条件:(1)mid=num(num为待查找的数据),查找成功,返回待查找数据在数组中对应的下标,即返回mid。
(2)序列中没有待查找的数据,循环到最后则会发现left的值小于了right的值,即left
代码实现如下:
while (left <= right) { mid = (left + right) / 2; if (arr[mid] < num) { left = mid + 1; } else if (arr[mid] > num) { right = mid - 1; } else { return mid; } }
最后对代码进行整合包装,完整代码如下:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int BinarySearch(int left, int right, int num, int arr[]); int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int right=sizeof(arr) / sizeof(arr[0]) - 1;//数组下标从0开始,所以需要减一 int left = 0; int num = 0; int mid = 0; printf("请输入你要查找的数字:"); scanf("%d", &num); mid=BinarySearch(left,right,num,arr); if (mid != -1) { printf("数字所在位置的下标为:%d\n", mid); } else { printf("找不到!\n"); } return 0; } int BinarySearch(int left,int right,int num,int arr[]) { int mid = 0; while (left <= right) { mid = (left + right) / 2; if (arr[mid] < num) { left = mid + 1; } else if (arr[mid] > num) { right = mid - 1; } else { return mid; } } return -1; }
效果展示: