道 · 引(引例)
一天小明考完试拿到成绩后,让小红猜一猜他考了多少分,并给出范围在56~65之间,小红随即问道你合格了吗??虽然这是扎心的一问,但我们可以窥见二分查找的思想在生活中广泛应用,小红根据小明的回答即可缩小一半的判断范围,不出几次小红便可锁定小明考取的分数,而不会选择遍历的思路,从56,57,一直猜到 65。
道 · 艺(规律方法)
我们在生活中不知不觉使用到了二分查找的方法,在编程刷题中也会遇到这一类型的题,那么该如何解决这一类型的题目呢,从而更好地指导我们的生活和学习。
首先二分查找的对象必须有序,即升序或降序排列,但注意此处有序不一定为等差(此处容易误判),其次我们通常使用数组来存储要处理的数据,则需要对元素下标进行处理,其步骤如下
- 找到中间元素k,其下标为mid
- 中间元素k和目标元素比较大小,确定新的查找范围,更换k值和mid值
- 返回上述两步直至找出或者耗尽查找范围
道 · 试(代码演示)
以小明,小红例子为例:每次用中间的分数缩小范围,找出小明分数的下标
#include<stdio.h>
int main()//二分查找
{
int arr[10] = { 56, 57, 58, 59, 60, 61, 62, 63, 64, 65 };
int left = 0, right = 9, mid=0;//起始最左最右端数据下标
int score = 0, i, j;
scanf("%d", &score);//录入小明取得的分数
while (left <= right)//循环缩小判断范围,折半寻找
{
mid = (left + right) / 2;//求出中间下标再与score比较缩小范围
if (arr[mid]<score)//所猜的中间值比实际值小
{
left = mid+1;
continue;
}
else if (arr[mid]>score)//所猜的中间值比实际值大
{
right = mid-1;
continue;
}
else//所猜的中间值与实际值相等
{
printf("找到啦,你的分数是%d,下标是%d\n", arr[mid],mid);
break;
}
}
if (left > right)
{
printf("你猜的分数超过范围啦\n");
}
return 0;
}
运行结果如下
当输入分数为65:
当输入分数超出范围:
道 · 味(总结回味)
提问:为何代码中出现的是 left = mid+1 和 right = mid-1 ?
释疑:求中间值下标是用到 mid = (left + right) / 2,这里的“ / ”号是除法取整,即9/2=4
则在算新的left和right时要加一与减一,详见图解。
见图解:
当 arr[mid]<score 即所猜的中间值mid比实际值score小,此时left右移至mid+1
当 arr[mid]》score 即所猜的中间值mid比实际值score大,此时right左移至mid-1
总结
- 学习到了如何用二分查找的方法提高查找效率,其时间复杂度为O(log2n),远优于遍历法
- 清晰了写代码时的易错点,为何有left = mid+1 和 right = mid-1 ,以及循环进行的条件left <= right中必有”=“号,因为此时所猜的中间值与实际值相等,也在循环内
- 当找不到所给数据时如何处理:if (left > right)