问题:假设我们有 12 万条这样的 IP 区间与归属地的对应关系,如何快速定位出一个 IP 地址的归属地呢?
二分查找的变形问题:
变体一:查找第一个值等于给定值的元素
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;
}
变体二:查找最后一个值等于给定值的元素
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 == n - 1) || (a[mid + 1] != value)) return mid;else low = mid + 1;}}return -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) {if ((mid == 0) || (a[mid - 1] < value)) return mid;else high = mid - 1;} else {low = mid + 1;}}return -1;
}
变体四:查找最后一个小于等于给定值的元素
public int bsearch7(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 ((mid == n - 1) || (a[mid + 1] > value)) return mid;else low = mid + 1;}}return -1;
}
解答开篇
如果ip区间和归属地的对应关系不经常更新,那么我们可以预先处理这12万的数,让其按照ip从小到大进行排序。将ip地址转化为32位整形数即可。那么该问题就转化为找到最后一个小于等于某个给定值的元素类型。
- 查询某个ip,先通过二分查找找到起始ip小于等于这个ip的ip区间,然后检查ip是否在这个ip区间内,如果在就返回对应的归属地显示;如果不在,就返回未查找到。