数据结构与算法之美
王争
前 Google 工程师
283752 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 81 讲
基础篇 (38讲)
数据结构与算法之美
15
15
1.0x
00:00/00:00
登录|注册

16 | 二分查找(下):如何快速定位IP对应的省份地址?

实现方法二
实现方法一
变体四:查找最后一个小于等于给定值的元素
变体三:查找第一个大于等于给定值的元素
变体二:查找最后一个值等于给定值的元素
变体一:查找第一个值等于给定值的元素
课后思考
内容小结
解答开篇
二分查找变形问题

该思维导图由 AI 生成,仅供参考

通过 IP 地址来查找 IP 归属地的功能,不知道你有没有用过?没用过也没关系,你现在可以打开百度,在搜索框里随便输一个 IP 地址,就会看到它的归属地。
这个功能并不复杂,它是通过维护一个很大的 IP 地址库来实现的。地址库中包括 IP 地址范围和归属地的对应关系。
当我们想要查询 202.102.133.13 这个 IP 地址的归属地时,我们就在地址库中搜索,发现这个 IP 地址落在[202.102.133.0, 202.102.133.255]这个地址范围内,那我们就可以将这个 IP 地址范围对应的归属地“山东东营市”显示给用户了。
[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 地址所在的区间,是非常耗时的。假设我们有 12 万条这样的 IP 区间与归属地的对应关系,如何快速定位出一个 IP 地址的归属地呢?
是不是觉得比较难?不要紧,等学完今天的内容,你就会发现这个问题其实很简单。
上一节我讲了二分查找的原理,并且介绍了最简单的一种二分查找的代码实现。今天我们来讲几种二分查找的变形问题。
不知道你有没有听过这样一个说法:“十个二分九个错”。二分查找虽然原理极其简单,但是想要写出没有 Bug 的二分查找并不容易。
唐纳德·克努特(Donald E.Knuth)在《计算机程序设计艺术》的第 3 卷《排序和查找》中说到:“尽管第一个二分查找算法于 1946 年出现,然而第一个完全正确的二分查找算法实现直到 1962 年才出现。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了二分查找的变形问题,包括查找第一个值等于给定值的元素、查找最后一个值等于给定值的元素,以及查找第一个大于等于给定值的元素和查找最后一个小于等于给定值的元素。作者首先介绍了二分查找的基本原理和简单实现,然后针对存在重复数据的有序数组,提出了相应的解决方案。通过比较不同的实现方法,强调了代码易读懂、无 Bug 的重要性。此外,作者还提到了二分查找的历史和难点,以及对于工程开发者来说,代码易读懂的重要性。文章通过具体的案例和代码实现,为读者提供了解决这类问题的思路和方法。文章还探讨了如何利用二分查找快速定位IP地址的归属地,以及二分查找在“近似”查找问题上的优势。最后,作者提出了一个课后思考问题,挑战读者对于循环有序数组的二分查找算法实现。整体而言,本文内容丰富,涵盖了二分查找的多个变形问题,对于读者快速了解和掌握二分查找算法具有重要参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《数据结构与算法之美》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(317)

  • 最新
  • 精选
  • Smallfly
    置顶
    有三种方法查找循环有序数组 一、 1. 找到分界下标,分成两个有序数组 2. 判断目标值在哪个有序数据范围内,做二分查找 二、 1. 找到最大值的下标 x; 2. 所有元素下标 +x 偏移,超过数组范围值的取模; 3. 利用偏移后的下标做二分查找; 4. 如果找到目标下标,再作 -x 偏移,就是目标值实际下标。 两种情况最高时耗都在查找分界点上,所以时间复杂度是 O(N)。 复杂度有点高,能否优化呢? 三、 我们发现循环数组存在一个性质:以数组中间点为分区,会将数组分成一个有序数组和一个循环有序数组。 如果首元素小于 mid,说明前半部分是有序的,后半部分是循环有序数组; 如果首元素大于 mid,说明后半部分是有序的,前半部分是循环有序的数组; 如果目标元素在有序数组范围中,使用二分查找; 如果目标元素在循环有序数组中,设定数组边界后,使用以上方法继续查找。 时间复杂度为 O(logN)。
    2018-10-27
    41
    636
  • 舍得
    第一段代码有漏洞,且不说int能不能表示数组的下标问题,毕竟这个数组能越界说明相当庞大了; 主要问题在于,如果我给定的数大于任何一个数组元素,low就会等于n,n是数组越界后的第一个元素,如果它刚好是要查找的值呢??

    作者回复: 谢谢指正 我稍后改下

    2018-10-27
    7
    73
  • 王艳红
    王老师,有一个疑惑不太明白 int mid = low + ((high - low)>>1) 这句,为什么要用这种写法呢?我看之前的简单的额二分查找是 int mid = (low + high)/2

    作者回复: 下面的写法有可能会导致溢出,比如low很大,high也很大,之和就溢出了。

    2019-03-05
    14
    59
  • Victor
    今天的IP地址归属地问题,从工程实现的角度考虑,我更偏向于直接使用关系型数据库实现。 也就是将12w条归属地与IP区间的开始、结束存入数据库中。 数据库表ip_table有如下字段:area_name | start_ip | end_ip ,start_ip及end_ip 均建立索引 SQL语句: select area_name from ip_table where input_ip >= start_ip and input_ip <= end_ip; 学习算法的课程常常和自己工程开发的实际结合在一起,感觉两者是相互促进理解的过程。

    作者回复: 数据库可以 单性能会受限

    2018-10-27
    9
    30
  • 疾风狂草
    老师,你说二分查找更适合用在“近似”查找问题,在这类问题上,二分查找的优势更加明显。这种问题链式哈希表不是更擅长吗?

    作者回复: 哈希表是精准查找

    2018-12-10
    8
  • helloworld2018
    老师你好,二分法查找在什么情况下low==high

    作者回复: low = 0 high=1,mid=0,low+1之后就相等了

    2019-08-05
    3
  • 小喵喵
    通过ip找归属地时,是二分查找最后一个ip小于等于给定值的ip,这只是开始区间,请问老师那结束区间如何找呢?

    作者回复: 找到区间开始就够了,因为区间是不重叠的。你自己举个例子看看。

    2019-10-16
    2
  • 小喵喵
    为什么mid == n - 1,不是mid==high来判断更好吗?

    作者回复: 你这行代码来自何处呀

    2019-10-16
    4
    2
  • 辣么大
    Donald E.Knuth 叫 高德纳。高德纳”这个中文名字是1977年他访问中国之前所取的,命名者是储枫(姚期智的夫人,计算机科学家)。他的妻子叫高精兰(Jill)。 这个名字不应该音译的。

    作者回复: 👍 麻烦编辑改下 多谢

    2019-04-23
    1
  • 小喵喵
    二分查找的变体问题,在java sdk、net framework中有实现吗?

    作者回复: c++有的

    2018-10-27
    1
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部