二分查找 BS
通过IP地址来查找IP归属地,IP地址是什么?
202.102.133.13
结果呢?
IP地址查询
此时这个查询是在一个很大的IP地址库中来实现。地址库中包括IP地址范围和归属地的对应关系。
二分查找最简单的情况是什么?
- 不存在重复元素
- 有序数组
- 查找 值=给定值的元素(这个是什么意思??)
典型的问题有以下几种——
典型的BS
变体1:查找第一个值等于给定值的元素
这个题目是什么意思呢?先看下图——
变体1:比如上面这样一个有序数组,其中,a[5],a[6],a[7] 的值都等于 8,是重复的数据。我们希望查找第一个等于 8 的数据,也就是下标是 5 的元素。
我们来看看变体1的代码实现——
public int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] > value) {
high = mid - 1;
} else if (a[mid] < value) {
low = mid + 1;
} else {
if ((mid == 0) || (a[mid - 1] != value)) return mid;
else high = mid - 1;
}
}
return -1;
}
我们需要注意的是:
a[mid]和value的关系有三种,大于小于等于;
high 和 low 的更新方式是这样的:high = mid - 1; low = mid + 1
- 上面的情况只应对了a[mid]<或者>value的情况,如果a[mid] = value呢?
我们需要做的就是确认这个a[mid]是不是第一个值等于给定值的元素
如果做到这个呢?我们有两种判断方法——
- 如果mid等于0,那么这个元素已经是该数组的第一个元素,那它一定是我们要找的。
- 如果mid不等于0,但是a[mid]的前一个元素a[mid-1]不等于value,那也说明a[mid]是我们要找的第一个值等于给定值的元素。
- 如果我们发现a[mid]前面的一个元素a[mid-1]也等于value,那说明此时的a[mid]肯定不是第一个,那我们应该怎么做呢?更新!,也就是更新high = mid - 1, 因为我们要找的元素肯定出现在[low, mid-1]之间。
变体2:查找最后一个值等于给定值的元素
我们再来分析一下最后一个值的情况——
- 如果a[mid]这个元素已经是数组中最后一个元素,那它肯定是我们要找的。
- 如果a[mid+1]的值不等于value,呢也说明a[mid]是要找的。
- 如果a[mid]后面的a[mid+1]也等于value, 那么我们就要更新low, 怎么更新呢?low=mid+1, 因为要找的元素肯定出现在[mid+1, high]之间。