最简单的二分查找状况下,咱们假设数组中没有重复元素,所以很容易实现。若是数组中存在重复元素,二分查找就没有想象中那么容易了。
若是数据中存在相同的元素,但咱们要查找第一个值等于给定值的元素,若是直接用最简单的二分查找,显然是不知足的。算法
看下面的例子,有 3 个等于 8 的元素,简单二分查找会返回 7,但第一个值等于 8 的元素应该是 a[5]。数组
其实,只要咱们在简单二分查找的基础上再多加上一点限制便可。数据结构
当咱们发现 a[mid] = val 时,咱们须要继续确认 a[mid] 左边还有没有等于 val 的元素。若 mid 左边没有和 a[mid] 相等的元素,则此时 a[mid] 就是咱们要找的第一个值等于给定值的元素。另外,若 mid 到了第一个元素的位置,说明左边已经没有元素,此时 a[mid] 也便是咱们要找的元素。不然,咱们就须要继续向左边查找。spa
float Binary_Search(float data[], int left, int right, float value) { int begin = left; while (left <= right) { int mid = left + (right - left) / 2; if (value == data[mid]) { if (mid == begin || a[mid - 1] != a[mid]) return mid; else right = mid - 1; } else if (value < data[mid]) { right = mid - 1; } else { left = mid + 1; } } return -1; }
这个问题和上面要查找第一个值等于给定值的问题思路同样,只不过是查找的方向改变了。code
当咱们发现 a[mid] = val 时,咱们须要继续确认 a[mid] 右边还有没有等于 val 的元素。若 mid 右边没有和 a[mid] 相等的元素,则此时 a[mid] 就是咱们要找的最后一个值等于给定值的元素。另外,若 mid 到达了最后一个元素的位置,说明右边已经没有元素,此时 a[mid] 也便是咱们要找的元素。不然,咱们就须要继续向右边查找。排序
float Binary_Search(float data[], int left, int right, float value) { int end = right; while (left <= right) { int mid = left + (right - left) / 2; if (value == data[mid]) { if (mid == end || a[mid + 1] != a[mid]) return mid; else left = mid + 1; } else if (value < data[mid]) { right = mid - 1; } else { left = mid + 1; } } return -1; }
当咱们发现 a[mid] >= val 时,咱们须要继续确认 a[mid] 左边还有没有大于等于 val 的元素。若 mid 左边的值小于 a[mid],则此时 a[mid] 就是咱们要找的第一个大于等于给定值的元素。另外,若 mid 到达了第一个元素的位置,说明左边已经没有元素,此时 a[mid] 也便是咱们要找的元素。不然,咱们就须要继续向左边查找。rem
float Binary_Search(float data[], int left, int right, float value) { int begin = left; while (left <= right) { int mid = left + (right - left) / 2; if (data[mid] >= value) { if (mid == begin || a[mid - 1] < a[mid]) return mid; else right = mid - 1; } else { left = mid + 1; } } return -1; }
当咱们发现 a[mid] <= val 时,咱们须要继续确认 a[mid] 右边还有没有小于等于 val 的元素。若 mid 右边的值大于 a[mid],则此时 a[mid] 就是咱们要找的最后一个小于等于给定值的元素。另外,若 mid 到达了最后一个元素的位置,说明右边已经没有元素,此时 a[mid] 也便是咱们要找的元素。不然,咱们就须要继续向右边查找。get
float Binary_Search(float data[], int left, int right, float value) { int end = right; while (left <= right) { int mid = left + (right - left) / 2; if (data[mid] <= value) { if (mid == end || a[mid + 1] > a[mid]) return mid; else left = mid + 1; } else { right = mid - 1; } } return -1; }
当咱们要查找 202.102.133.13 这个 IP 地址的归属地时,咱们就在地址库中搜索,发现这个 IP 位于 [202.102.133.0, 202.102.133.255] 这个范围内,咱们就能够找到对应的归属地——山东东营。it
[202.102.133.0, 202.102.133.255] 山东东营市 [202.102.135.0, 202.102.136.255] 山东烟台 [202.102.156.34, 202.102.157.255] 山东青岛 [202.102.48.0, 202.102.48.255] 江苏宿迁 [202.102.49.15, 202.102.51.251] 江苏泰州 [202.102.56.0, 202.102.56.255] 江苏连云港
所以,咱们能够按照 IP 地址库的起始地址对全部区间进行排序,而后问题就转化为了找到最后一个起始地址小于等于给定 IP 地址的区间。class
获取更多精彩,请关注「seniusen」!