数据结构和算法之——二分查找下

最简单的二分查找状况下,咱们假设数组中没有重复元素,所以很容易实现。若是数组中存在重复元素,二分查找就没有想象中那么容易了。

1. 查找第一个值等于给定值的元素?

若是数据中存在相同的元素,但咱们要查找第一个值等于给定值的元素,若是直接用最简单的二分查找,显然是不知足的。算法

看下面的例子,有 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;
}

2. 查找最后一个值等于给定值的元素?

这个问题和上面要查找第一个值等于给定值的问题思路同样,只不过是查找的方向改变了。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;
}

3. 查找第一个大于等于给定值的元素?

当咱们发现 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;
}

4. 查找最后一个小于等于给定值的元素?

当咱们发现 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;
}

5. 如何快速定位 IP 对应的省份?

当咱们要查找 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」!

相关文章
相关标签/搜索