目录
前言引入
二分查找的原理大家可以回想一下高中数学中我们用二分法求函数的零点的思路!现在回到编程领域,我们要在一个升序的区间【left,right】,要中查找一个数find,遵循如下原则(mid=left+(right-left)/2)
1.如果mid大于find,则下一次在区间【left,mid-1】中查找,因为f(mid)>find,所以查找区间的右边界right=mid-1
2.如果mid小于find,则下一次在区间【mid+1,right】中查找,因为f(mid)<find,所以查找区间的左边界left=mid+1
3.如果mid恰好等于find,输出mid,如果数组是从下标为0开始存储的,mid+1便是要查找数据所在的位置,如果数组是从下标为1开始存储的,mid便是要查找数据所在的位置
然后一直重复着这个过程,直到中间找到数据或者left>right便退出循环~
计算mid应该注意的细节
我们在每进行一次判断前,都要重新计算一下mid,然而许多人都是用mid=(left+right)/2去计算,其实这个有时候是不好的,因为如果基数很大,left+right可能会超过long long 型的数据范围,而导致数据精度的丢失,如果用mid=left+(right-left)/2去计算,则可以在一定程度上避免这个问题~ 而防爆数据范围的方法有许多,有待大家去慢慢发现,博主在这里就不做过多的阐述了~
题目
许多人明明代码对了,为什么还会wa呢? (๑•̌.•̑๑)ˀ̣ˀ̣这便是对这个题目中位序的错误理解,他不同于位置(位序=位置-1),所以5的位序便是0,92的位序便是10.
代码演示
#include <iostream>
#include <algorithm>
using namespace std;
int sum = 0, a[10005];
int f(int left, int right, int find)
{
int zhong;
while (left <= right)
{
sum++;
zhong = left + (right - left) / 2;
if (a[zhong] > find)
right = zhong - 1;
else if (a[zhong] < find)
left = zhong + 1;
else
return zhong;
}
return -1;
}
int main()
{
int i, find, n;
cin >> n;
for (i = 0; i < n; i++) cin >> a[i];
cin >> find;
cout << f(0, n - 1, find) << endl << sum;
return 0;
}
小结
其实这是二分查找的简单版本的一种表现形式,但实际中我们会遇到像查找一个数据,如果数组中有相同的数据返回最后(最前面)一个数据的位置等问题,这里博主强烈安利下面朋友的这篇博客,二分查找与二分答案
希望对各位有所帮助~
🥂(❁´◡`❁)您的点赞➕评论➕收藏⭐是作者创作的最大动力🤞