
巴尔加瓦
本书示例丰富,图文并茂,以简明易懂的方式阐释了算法,旨在帮助程序员在日常项目中更好地利用算法为软件开发助力。前三章介绍算法基础,包括二分查找、大O表示法、两种基本的数据结构以及递归等。余下的篇幅将主要介绍应用广泛的算法,具体内容包括:面对具体问题时的解决技巧,比如何时采用贪婪算法或动态规划;散列表的应用;图算法;K最近邻算法。本书适合所有程序员、计算机专业相关师生以及对算法感兴趣的读者。
相当不错的一本入门级算法书。 曾看到过一句话,算法是“科技变革的底层引擎”。 想想自己过去十多年的程序员生涯,最后悔的就是没有编写过比较深刻,惊艳且实用的算法用在生产环境中,将很多精力放在了设计模式,架构设计,分布式设计上,后来做了技术管理后,就更加不能接触到算法了,为此遗憾不已。 如今拿起这本书,看到了熟悉的数据结构,数组,链表,散列表,集合等等,还看到了很多使用的排序规则,快速排序,二叉树搜索,红黑树等等。本是一些十分专业的概念,而作者图文并茂地讲解了很多基础知识,让读者引人入胜于其中。 思考一下当今生活,很多算法的应用。 1,我们听歌,看视频,APP总会根据我们经常听的歌曲或者电影推荐给我们类似的曲目或电影,其背后就是K邻近算法。 2,我们开车,导航会推荐几条建议路线,其背后就是以Dijkstra(迪杰斯特拉)算法为基础的各种算法。 3,外卖平台,网约车派单等都是通过背后的启发式优化算法如蚁群算法,遗传算法等来实现的。 其他如人工智能,AI机器人就更加不用说了,难度就在于各种算法。如果说要给未来年轻人给点学习和就业上的建议,如果对数学感兴趣,那就去研究算法。各种学校研究机构,大厂,AI公司,机器人公司以及各行各业,养猪,种植,市政规划,物流,铁路航空等等都是急需这样的人才的,还是那句话:学好数理化,走遍天下都不怕,尤其是数学,重中之重啊!
本书图文并茂,用通俗易懂语言介绍什么是算法的基础知识。常言道,一图抵百字,翻过本书后,不服都不行?就像读儿童时期连环画一样,读它居然初步认识了计算机算法的一些基本知识,非常喜欢! 常言还说,不要只埋头拉车不看路,本书说白了,不仅仅是看路,而且是看你一条路走是又快又好。了解它,当然本书希望是帮助设计人员通过好的途径,可令计算机获得最佳优选择算法。 本是介绍的就是其中的一些原理。例如,“算法的速度指的并非时间,而是操作数的增速。 ❑ 谈论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。 ❑ 算法的运行时间用大O表示法表示。 ❑ O(log n)比O(n)快,当需要搜索的元素越多时,前者比后者快得越多”。 ............. 简言之,它虽然说看起来简单,实际上它提供给普通读者的,还真有些像“内行看门道 ,外行看热闹”高招。本书语言不多,道理深。因为它本身也是水很凉很深,在里面游不一定舒服,除非是哪些会玩的,不得不学或者强壮....呵呵! 好在作者非常厚道,他也告诉读者那些内容不必读。 本书关键字就是搜索!这本小册子中的作业居然还附有答案!
算法使人聪明,本书使人愚蠢! 首先,结构混乱. 讲算法,里面又插入数据结构的内容, 讲数据结构,又不讲齐全, 讲不下去了,就一句话:后面你就知道了. 其次,概念不清. 第二章讲递归,把循环和递归搅拌不清, 讲不清楚了,又加入了栈的内容. 栈讲的糊里糊涂,就结束了. 突然提出一句:为什么要学习递归? 因为有些语言没有循环. 正如书友评论: 现在还有哪个语言没有循环的? 第三,举例混乱 本书号称图解, 除了老祖母的箱子之类,和算法没多大关系, 而且增加理解难度的插图以外, 其余图解,就是手绘内存图 而且写到0,都要用φ, 特别容易和专用符号混淆, 和任何一个学校的板书有什么区别? 图解的意义何在? 本来对算法和Python有点了解 本书只用3章就让我彻底混乱. 它让我想起了开培训班圈钱的“水师” 大水漫灌,还情真意切的说: 我知道的太多了,想全都告诉你们, 只可惜长8张嘴都不够 既然,8张嘴都说不清,何不shut up !
瑕不掩瑜 我会这样定义一本我眼中的好书:深入浅出、关联丰富以及与我当下的认知水平相当。 这本小书的最大优点就在推理过程交代清楚。一步一步、为什么这么想、这么走,都给你描画得一清二楚。换言之,它是按照事物发展的逻辑顺序进行内容构建的,看得就很过瘾,像一本推理小说。 举例而言,它会在介绍完 SHA 算法后立刻介绍局部敏感的散列算法,在我刚在前一节中提出问题,如果我不想一点变动就让哈希值完全不同,那么应如何处理?它在下一节立刻垫上了,用 Simhash。这种逻辑上的完备与层层递进,就减少了很多理解成本。有时候你觉得理解困难,就是因为中间有步骤被抽去了,例如你在数学书里经常看到的:显然可得、易证得。 所以这是一本看起来很过瘾的小书。细嚼慢咽,给你剥出来最精华的内核。 但有一个错误我觉得是不该发生也不能被容忍的。在第七章,狄克斯特拉算法中,有明显错误。作者指出,狄只适用于有向无环图。而这是不正确的,事实上,只要没有负权边就可以。我在这里思路衔接不上,因为从算法实现中推不出作者言之凿凿的结果,最后经外部确认,才发现是作者出错。 看得出,作者对这个算法本身也理解不透彻。很多地方,没有讲透。例如在顶点选取上,为什么是选取当下可选点中,值最小的那个?因为在没有负权边的图中,它是已经被固定了的,因为要走其他任何一点再回到该顶点,都会造成值更大。而更新每个顶点的最小值,就是这个算法的核心,也是最机智、最动人、最美的地方。 也就是动态规划。前序的最优子结构,后面都可以直接拿来用,而且只要没有负权边,就满足无后效性的条件。但是作者既没有讲到上面那句缺失的话,让这个问题在我脑子里多思考了大半天,直到在另一本《我的第一本算法书》中才得到启发;也没有联系动态规划或者贪婪算法。或许略难,但是可以提一提,一带而过。 对了,这本书建议结合《我的第一本算法书》一起看,微信读书里也有,另外建议下载配套 app 一起使用方便理解,app 叫做 Algorithms。 因为这本书出版好些年了,这种硬伤还没有被更正,就让我不能接受。但是整体上瑕不掩瑜,是很好的入门书。况且它也给到学有余力的同学继续探索的空间。我非常喜欢他常常在篇末写的,如果你对这个话题感兴趣,欢迎你继续沿着某某算法的脚步朝里面研究。我非常喜欢这种引导。 最后,阅读算法书请配合力扣。我之所以会盛赞这本书,认为作者很多地方讲透了,就是因为很多章节我一看完,或者看了一半,就忍不住想开力扣开始刷相关标签的题目。动规、二分尤甚。这就是他把我讲明白了的最好说明。 最后的最后提醒自己,多找这类书看就够了,不要看鸡零狗碎的算法公众号,除非你能联系上作者能进一步沟通交流,不然直接读书才是最有效率的方式。出版书通常作了更好的排序工作,而且因为编辑的存在,错误也更少。 公号的错别字就够喝一壶,作者的自身理解不够,你看文章有如猜谜,更加难懂。
《算法图解》拆解 作者:[美]巴尔加瓦 一、一句话概括 学习算法不是为了背代码,而是掌握一组解决问题的思维模型:怎样缩小搜索范围、怎样选择数据结构、怎样拆分问题,以及怎样在时间、空间和解的质量之间作出权衡。 二、核心逻辑 全书按照“基础—策略—应用—延伸”的路线展开: 1. 基础:二分查找、大O表示法、数组、链表、递归和栈。2. 核心策略:分而治之、快速排序、散列表和图搜索。3. 问题求解:最短路径、贪婪算法、动态规划和K最近邻。4. 延伸方向:树、倒排索引、并行计算、MapReduce、概率型数据结构、密码学和线性规划。 学习路径可以概括为: 先判断数据规模 → 选择合适的数据结构 → 识别问题类型 → 选择算法策略 → 分析时间与空间复杂度 → 用测试验证边界条件 本书用大量图示降低算法门槛,重点在直觉和应用,而不是严格数学证明。 三、核心内容 1. 算法是解决问题的步骤,复杂度描述增长速度 两个算法都能得到正确答案,但数据规模扩大后,运行时间可能差异巨大。 大O表示法关注输入规模增长时,操作次数怎样变化。 常见复杂度包括: O(1):常数时间;O(log n):对数时间;O(n):线性时间;O(n log n):高效排序常见复杂度;O(n²):双重遍历;O(2ⁿ)和O(n!):组合爆炸。 大O通常忽略常数项和低阶项,适合比较增长趋势,而不是精确预测运行秒数。 2. 二分查找通过不断排除一半数据提高效率 在有序数据中,二分查找先检查中间元素: 如果目标更小,排除右半部分;如果目标更大,排除左半部分;然后在剩余一半中重复。 每一步都把搜索范围减半,因此复杂度是O(log n)。 它的前提是数据有序,并且能够高效访问中间位置。若数据未排序,还要考虑排序成本。 3. 数组和链表代表两种存储权衡 数组把元素连续存放,因此通过索引读取通常很快。 链表的节点可以分散存放,每个节点保存下一个节点的位置,因此插入和删除更灵活,但随机访问较慢。 简单比较: 数组擅长按位置读取;链表擅长在已知位置附近插入和删除;数组通常具有更好的缓存局部性;链表需要额外指针空间;实际语言中的动态数组能够兼顾多种操作。 数据结构选择应根据最频繁的操作,而不是抽象地判断谁更好。 4. 选择排序直观展示“寻找+删除”的成本 选择排序每次从未排序元素中找出最小值,再放到结果中的正确位置。 寻找最小值需要遍历剩余数据,整个过程重复多次,因此时间复杂度是O(n²)。 选择排序实现简单,却不适合大规模数据。 它的教学意义在于帮助读者理解:一个容易描述的步骤反复执行,可能产生平方级成本。 5. 递归让函数用更小的问题解决原问题 递归函数会调用自身,把当前问题缩小。 每个递归都需要两个部分: 基线条件:何时停止;递归条件:怎样把问题缩小并继续调用。 缺少正确基线条件会导致无限递归或栈溢出。 递归适合表达树、分治和回溯等结构,但不一定比循环更快。其优势往往是代码更接近问题定义。 6. 调用栈保存函数执行状态 函数调用时,系统需要保存局部变量、返回地址和当前执行位置,这些信息进入调用栈。 栈遵循“后进先出”: 新调用压入栈顶;函数完成后从栈顶弹出;程序回到上一级调用。 递归层数太深会占用大量栈空间。因此,分析算法时不仅要看时间,也要看递归带来的空间成本。 7. 分而治之把复杂问题拆成相似子问题 分而治之通常包含三步: 1)找到最简单的基线情况;2)把原问题拆成更小的同类问题;3)合并子问题的结果。 快速排序、归并排序和二分查找都体现了这种思想。 分而治之的关键,是拆分后子问题更小,并且解决子问题能够直接支持原问题。 8. 快速排序依赖基准值和分区 快速排序选择一个基准值,把其他元素分成小于基准和大于基准的两组,然后分别递归排序。 平均情况下,其时间复杂度为O(n log n)。 如果每次基准选择极差,分区严重不平衡,最坏情况会退化为O(n²)。 实际实现通常通过随机基准、三数取中或小数组切换其他排序等方式降低风险。 9. 散列表用计算位置实现快速查找 散列函数把键映射到数组位置,使插入、查找和删除在平均情况下接近O(1)。 散列表可用于: 字典和映射;缓存;去重;频次统计;检查是否访问过;建立对象索引。 不同键可能映射到同一位置,这叫散列冲突。冲突处理和负载因子会影响实际性能。 散列表依赖良好的散列函数和容量管理,并不保证每次操作都严格是O(1)。 10. 图用于表示关系网络 图由节点和边组成。 边可以是有向或无向,也可以带有权重。社交关系、道路、依赖、通信和任务流程都可以表示为图。 图通常使用: 邻接表;邻接矩阵。 稀疏图更适合邻接表,边非常密集或需要快速检查节点是否直接相连时,邻接矩阵可能更合适。 11. 广度优先搜索寻找无权图的最短路径 广度优先搜索从起点开始,先访问距离一条边的节点,再访问距离两条边的节点。 它使用队列保持“先进先出”顺序,因此第一次到达某个节点时,路径通常就是边数最少的路径。 BFS可用于: 查找最近关系;无权图最短路径;层级遍历;判断可达性;网络广播。 必须记录已经访问的节点,否则在包含环的图中可能无限重复。 12. 狄克斯特拉算法处理非负权图的最短路径 当每条边成本不同,单纯按边数搜索不再适用。 狄克斯特拉算法反复选择当前成本最低的未处理节点,并更新经过该节点到达邻居的成本。 它适用于边权非负的图。 如果存在负权边,已经确定的最短距离仍可能被后续路径降低,算法就会失效。此时需要Bellman-Ford等其他方法。 13. 贪婪算法每一步选择当前最优 贪婪算法不回头修改之前的选择,因此通常实现简单、速度快。 在教室调度等问题中,选择最早结束的活动能够得到全局最优。 但在背包等问题中,局部最优不一定组成全局最优。 使用贪婪策略时,应判断问题是否具有贪婪选择性质,并尽可能证明结果,而不是因为策略直观就默认正确。 14. NP完全问题提醒我们接受近似解 某些组合问题的可能方案随规模快速增长,目前没有已知的高效通用精确算法。 判断一个问题可能属于NP完全问题的线索包括: 需要尝试大量组合;很难找到有效缩小搜索空间的方法;与旅行商、集合覆盖等经典问题相似;输入稍微增大,精确搜索就无法承受。 面对这类问题,可以使用: 近似算法;贪婪方法;启发式搜索;随机算法;限定问题规模;接受时间与质量权衡。 知道何时停止追求精确解,是重要的工程能力。 15. 动态规划保存重复子问题的结果 动态规划适用于可以拆成相互重叠子问题,并具有最优子结构的问题。 它通常使用表格保存较小问题的最优结果,避免反复计算。 背包问题中,表格可以按物品和容量逐步构建;最长公共子序列或子串也可以使用二维状态表。 动态规划的关键是正确设计: 状态表示;状态转移;初始条件;计算顺序;最终答案位置。 找到状态定义,往往比写循环更困难。 16. K最近邻依靠相似样本进行预测 K最近邻算法找到距离新样本最近的K个已知样本,再根据它们的类别投票或数值平均。 它可以用于分类、回归和简单推荐。 关键问题包括: 怎样定义距离;特征是否需要标准化;K值如何选择;无关特征是否干扰相似性;数据量大时查询是否太慢。 KNN几乎没有显式训练过程,但预测时需要保存并搜索大量数据。 17. 推荐系统的基础是定义“相似” 用KNN构建推荐时,可以根据用户评分、行为或物品属性计算相似度。 如果两个用户偏好相近,可以用其中一人的选择推测另一人可能喜欢什么。 但现实推荐系统还需要处理: 数据稀疏;新用户和新物品;热门偏差;相似度尺度;兴趣变化;计算效率;多样性与探索。 简单KNN适合建立推荐直觉,大规模系统通常还会使用矩阵分解、深度模型和在线反馈。 18. 树、倒排索引和概率型结构扩展算法工具箱 书末介绍多种后续学习方向: 树和二叉搜索树用于层级数据与有序查找;倒排索引用于搜索引擎,从词定位文档;布隆过滤器以少量内存判断元素可能是否存在;HyperLogLog近似统计不同元素数量;局部敏感散列用于快速寻找相似项。 这些方法展示了工程中的常见权衡:允许少量误差,可以换取显著的速度或空间优势。 19. 并行算法和MapReduce处理大规模数据 当单机无法高效处理任务时,可以把数据和计算拆到多个节点。 MapReduce把工作分为: Map:对数据分片执行相同处理;Reduce:汇总中间结果。 分布式计算不仅要考虑算法本身,还要处理网络、数据移动、节点故障和负载均衡。 能够并行不代表一定更快,小规模任务的通信成本可能超过计算收益。 20. 密码学算法建立数字信任 SHA等哈希算法把任意输入转换为固定长度摘要,可用于完整性检查和密码存储等场景。 Diffie-Hellman允许通信双方在公开信道上协商共享密钥。 密码学安全依赖经过广泛检验的算法和正确实现,不能自行设计“看起来很复杂”的加密方案。 算法知识不仅用于提高速度,也用于建立安全边界。 21. 本书强调直觉,但不是完整算法教材 本书通过图解和简单Python代码帮助初学者建立直觉,适合第一次系统接触算法。 为了易懂,它简化了部分证明、边界条件和工程实现。 读完后还需要继续学习: 更严格的复杂度分析;正确性证明;更多数据结构;图的高级算法;实际语言库的实现;缓存与硬件性能;并发和分布式系统。 图解是入口,而不是算法学习的终点。 四、本书最值得关注的核心观点 本书最值得关注的观点是: 选择算法之前,先识别问题结构。 如果数据有序,可以考虑二分查找;如果问题是关系网络,可以建图;如果要寻找无权最短路径,可以用BFS;如果包含非负成本,可以考虑狄克斯特拉;如果子问题重复,可以使用动态规划;如果精确求解成本过高,则应考虑贪婪或近似方法。 真正的算法能力不是记住更多代码,而是能够把现实问题映射到熟悉结构,并理解这种映射所依赖的前提。 五、一段话总结 《算法图解》以图示和Python示例介绍二分查找、大O复杂度、数组与链表、递归与调用栈、分而治之、快速排序、散列表、图、广度优先搜索、狄克斯特拉算法、贪婪算法、动态规划和K最近邻,并延伸到树、倒排索引、MapReduce、布隆过滤器、HyperLogLog和密码学。全书的重点不是背诵实现,而是识别问题结构:有序数据可以缩小一半搜索范围,关系问题可以建图,重复子问题可以保存结果,规模过大的组合问题则应接受近似解。虽然本书为了易懂简化了部分证明和工程细节,但它清楚展示了算法思维的核心——在正确性、时间、空间和解的质量之间作出有根据的选择。
遇到这样一本有趣的算法书籍后,你就会意识到,学习算法也可以像看喜欢的小说一样令人沉醉。 未学习过算法的,读完本书,以后的算法学习之路将会一帆风顺。对于熟悉算法的同学,本书也可以加深你的理解,有些晦涩难懂的概念和动态规划等等,根本无需死记硬背。当你想到某个算法时,你脑海中,就会自动绘制出一幅相关景象了。 后悔这么晚遇到它。
很好的一本算法入门书,不过封面标榜的像小说一样有趣,应该写在《算法之美》上更适合。 算法跟哲学有点儿类似,言简意赅又包罗万象,由些许个例高度抽象出来的规律,可以无限延伸扩展,都引发深度思考。不同在于,哲学由于其天生的多面性、不确定性,容易培养成流氓性质的诡辩思维,案例古今中外比比皆是。算法虽然没有像数学一样的精确性,但大体上是向准确性靠拢的,准确或者近似准确。也正因为这一点,算法才得以在各行各业大行其道,这也是社会物质条件越来越便利,物联网必然兴起的理论基础。反向来看,透过现象看实质,从社会治理,政策调控,经济规划,工业设计等方面看,其背后都有一些若隐若现的极其相似的东西,这些相似的东西,应该也可以称之为算法吧。
算法真的很有意思,看到停不下来。这本书文字与图片结合,讲的很通俗,很容易理解。比较感兴趣的几个算法:动态规划,广度优先,Dijkstra加权图最短路径,分治法。学习算法重在思考,对问题思考的过程比解决问题本身更重要。好的算法能够优雅地解决复杂的问题,让人叹为观止。
这是我看过的最好的关于算法的抛砖引玉之作。能把算法这种连专业人员都倍感困难的内容讲得像读故事一样通俗易懂的书实属罕见。本书图文并茂,平易近人,是算法初学者的首选佳作。从未学过算法的,看过此书,今后算法的学习将一凡风顺。学过算法的,此书将让你不再惧怕算法,和算法做朋友。
《算法图解》这本书给我的最大感受是:它不是在教我“多厉害的算法”,而是在教我“如何正确地看待算法”。 在阅读这本书之前,我对算法的印象更多停留在“面试必备”“刷题工具”“难而且枯燥”。算法像是一道道孤立的题目,记住解法就算过关。但《算法图解》用一种极其直观、循序渐进的方式,把算法从“抽象符号”拉回到了“解决问题的工具”这个本质上。 一、图解的力量:把“想不通”变成“看得懂” 这本书最大的特点就是“图多字少”。无论是二分查找、广度优先搜索,还是狄克斯特拉算法,作者都会先画出一步一步发生了什么,而不是一上来就给公式或伪代码。 这种方式让我第一次意识到: 算法难,并不是因为它复杂,而是因为我们没看到过程。 当搜索过程、路径选择、状态变化被画出来之后,很多“为什么要这么做”的问题,其实会自己消失。 二、算法不是技巧,而是思维方式 《算法图解》反复强调一个核心思想:算法的价值,在于减少无谓的尝试。 比如: 二分查找,本质是“每一步都排除一半不可能” BFS,是“层级推进,保证最先到达的一定最短” Dijkstra,是“每次做一个永远不会后悔的选择” 这让我开始用算法的视角重新看待日常问题:不是“我能不能做出来”,而是“有没有办法更快排除错误路径”。 三、对时间复杂度的直觉被真正建立起来了 以前看到 O(n)、O(n log n),更多是一种“背概念”的状态。而这本书通过对比操作次数、画增长曲线的方式,让我真正建立起了直觉。 我开始能在写代码时自然地问自己: 这个循环会跑几次? 数据量翻十倍会发生什么? 这个解法是不是在“重复做无意义的事”? 这是一个从“能写代码”到“写得更聪明”的转折点。 四、它降低了算法的心理门槛 《算法图解》没有试图一次性讲完所有高级算法,而是非常克制地只选择最核心、最常用的那一部分。 这反而让我意识到: 算法不是一座必须一口气爬完的山,而是一条可以慢慢走的路。 掌握好搜索、排序、图、动态规划的基本思想,就已经能解决大量真实问题,而不是为了“算法很牛”而学算法。 五、读完之后的意识转变 读完这本书后,我最大的变化不是“我记住了多少算法”,而是: 不再下意识地回避算法问题 遇到复杂逻辑,开始主动拆解状态和选择 更愿意问“有没有更优的思路”,而不是“先凑个能跑的” 这本书更像是一位耐心的引路人,而不是一个站在高处的考官。