【图书阅读】《Aditya Bhargava-算法图解:像小说一样有趣的算法入门书》

这本书主要讲述了算法基础,包括二分查找、大O表示法、两种基本的数据结构等,后续也面对具体问题时的技巧,例如贪婪算法或动态规划:散列表的应用:图算法;K最近邻算法。该篇博文主要记录阅读完的一些重点回顾!这本书确实比较有趣,通俗易懂!安利!

目录

1 算法:二分查找

2 算法运行时间:大O表示法

3 数据结构:数组

4 数据结构:链表

5 排序算法:选择排序

6 编程方法:递归

7 数据结构:栈

8 排序算法:快速排序

9 数据结构:散列表

10 图算法:广度优先搜索

11 数据结构:队列

12 图算法:狄克斯特拉算法

13 算法:贪婪算法

14 算法:动态规划算法

15 算法:K最邻近算法


1 算法:二分查找

  • 思路:以猜数字为例,A在0-100以内任意选择一个数字,B猜数字,A只会回答大了/小了,直到B猜对位置,此时,B所有的猜测次数可能是到猜遍所有数字才成功,二分查找则在猜测过程中进行优化,取剩余猜测范围的中间值进行猜测那么猜测的次数显然会减少很多,这就是二分查找。
  • 要求:给定的范围内元素是有序的;也就是说,输入的是有序的元素列表。
  • 思考:假设一个包含128个名字的有序列表,使用二分查找在其中查找一个名字,请问最多需要几步才能找到?
    • 128➡️64➡️32➡️16➡️8➡️4➡️2➡️1      7步
    • 如果列表长度翻倍呢?
    • 256➡️128➡️64➡️32➡️16➡️8➡️4➡️2➡️1     8步
  • 总结:2^{n} < N    //    log N < n (N表示元素个数;n表示步数)

2 算法运行时间:大O表示法

  • 格式:O(n), 这里的n表示操作数。
  • 概念:表示算法的操作数,表示算法的运行时间。不以秒为单位。
  • 作用:指出算法的运行时间的增速,指出了最糟糕情况下的运行时间。
  • 注意:操作数的常数往往会被省略!
  • 举例:
    • 简单查找:O(n)
    • 二分查找:O(log n)
  • 思考:大O表示法给出各种情况的运行时间
    • 在电话本中根据名字查找号码:O(log n)
    • 在电话本根据电话号码找人:O(n)
    • 阅读电话本每个人的电话号码:O(n)
  • 补充:常量c-算法所需要的固定时间。通常不考虑这个常量,因为算法的大O运行时间不同,这种常量无关紧要!

3 数据结构:数组

  • 思路:以电影院的座位为例,人(元素)坐在不同的座位(内存)上,每个座位都有自己的编号(地址)。当一群好朋友往往会坐在一起(连续)中,就是数组的概念。
  • 性质:
    • 数组元素在内存中是相连的;
    • 元素的类型都必须相同(int ,double)。
    • 数组直接映射到内存。
  • 思考:
    • 读取元素O(1):因为是连续的元素,直接根据地址进行访问。支持随机访问!
    • 添加元素O(n):好朋友做完后,其他人也落座之后,又来了几个好朋友,怎么办?重新分座位!!
    • 删除元素O(n):坐完之后,其中几个好朋友临时有事离开了,怎么办?重新分座位!!好烦呀!

4 数据结构:链表

  • 思路:以电影院的座位为例,人(元素)坐在不同的座位(内存)上,每个座位都有自己的编号(地址)。当一群好朋友任意坐在电影院的座位(离散),各自记住后一个朋友做的位置,就是链表的概念。
  • 性质:
    • 链表的元素可以存储在内存的任何地方;
    • 每个元素都存储了下一个元素的地址,从而使一系列随机的内存地址串在一起。
    • 链表直接映射到内存。
  • 思考:
    • 读取元素O(n):因为是离散的元素,需要根据元素知道后一个元素位置实现访问。
    • 添加元素O(1):好朋友坐完后,其他人也落座之后,又来了几个好朋友,怎么办?告诉原先坐好的最后一个朋友,坐下的位置!
    • 删除元素O(1):坐完之后,其中几个好朋友临时有事离开了,怎么办?把还在的朋友的位置转告给前一个还在的朋友!

5 排序算法:选择排序

  • 思路:以电影评分为例,将电影与评分一并放入列表,现在需要将电影按照评分由高到低进行排序。需要依次将列表高评分电影进行选择,同时将其在取出时将原列表对应删除。随着排序的进行,每次需要检查的电影评分(元素数)在逐渐减少。
  • 算法运行时间:O(n*1/2n)➡️O(n*n) ,常数往往会省略哦!

6 编程方法:递归

  • 递归函数=基线条件+递归条件,避免形成无限循环。
    • 递归条件:函数调用自己
    • 基线条件:函数不在调用自己

7 数据结构:栈

  • 思想:以便利贴为例,生活中用便利贴(栈)记录事项,当事项记录完毕时,常常撕下来粘到别的地方;因为便利贴默认从上往下撕,这对应着栈弹出(删除并读取)。当然,有时发现一张单独的便利贴还未用,将其粘到便利贴本,这对应着栈的压入(插入)。
  • 操作:压入(插入)和弹出(删除并读取)
  • 性质:后进先出,不能随机地访问队列中的元素!
  • 思考:调用栈可能很长,这将栈用大量的内存,如果递归函数陷入了无限循环,这意味着什么?后果是什么?
    • 实际上,函数每次调用时,计算机都将为其在栈中分配内存。
    • 递归函数无限循环,栈将不断地增大。每个程序可使用的调用栈空间都有限,程序用完这些空间后,将因栈溢出而终止。

8 排序算法:快速排序

  • 分而治之:递归式问题解决方法。
  • 分而治之算法:快速排序。
  • 思想:找出简单的基线条件;确定如何缩小问题的规模,使其符合基线条件。
  • 快速排序:函数qsort (C)、quicksort(Python)
    • 选择基准值:从数组选择的一个元素;决定排序速度!
    • 将数组分成两个子数组:小于基准值的元素和大于基准值的元素。
    • 对两个子数组进行快速排序。
  • 算法运行时间:O(n*log n)
  • 快速排序的性能高度依赖选择的基准值。
  • 思考:用大O表示法时,下列各种操作时间:
    • 打印数组中的每个元素:  O(n)
    • 将数组的每个元素都乘以2: O(n)
    • 只将数组中的第一个元素的值乘以2: O(1)

9 数据结构:散列表

  • 思想:以销售员为例,无论问询哪间商品的价格,她都能迅速回答出正确的价格。
  • 散列函数:
    • 就是上述的销售员,即无论给它什么数据,都还你一个数字。
    • 专业而言,散列函数"将输入映射到数字"。
      • 散列函数必须是一致的,即输入输出保持固定不变。
      • 散列函数应将不同的输入映射到不同的数字。
      • 散列函数知道数组有多大,只返回有效的索引。
  • 散列表:散列函数和数组联合的数据结构,是一种包含额外逻辑的数据结构,使用散列函数确定元素的存储位置。
    • Python提供的散列表实现为字典:函数dict
    • 散列表=键key+值value,散列表将键映射到值。
  • 思考:散列表的案例
    • 模拟映射关系,用于查找:电话本
    • 防止重复:投票
    • 缓存/记住数据:服务器将部分内容存于本地,避免长时间处理生成常用页面。
  • 冲突:散列函数不满足-将不同的键映射到数组的不同位置;即给两个键分配的位置相同!值存在覆盖的风险!
    • 简单思路:如果两个键映射到了同一个位置,就在这个位置存储一个链表!
    • 思考:所有键存到了同一个位置,导致链表特别长,其他位置又很空闲!重新思考散列函数!
    • 避开最糟糕情况,避免冲突:较低的填装因子和良好的散列函数。
      • 填装因子:散列表包含的元素数/位置总数;度量散列表中有多少位置是空的。建议大于0.7,就调整散列表的长度!
  • 散列表性能:
    • 平均情况下,散列表执行各种操作的时间O(1);最糟糕的情况,O(n)。
    • O(1):常量时间,表示不管散列表多大,所需要的时间都相同。

10 图算法:广度优先搜索

  • 广度优先搜索:找寻两样东西的最短距离;解决最短路径问题的算法。
  • 图:图模拟一组连接。图由节点(node)和边(edge)组成,一个节点可能与众多节点直接相连,这些节点被称为邻居。
    • 有向图:有箭头;单向邻居。
    • 无向图:无箭头;互为邻居。
  • 思想:以找寻芒果商为例,首先咨询直系关系(家人、朋友),称为一度关系;发现都没有关系,通过直系关系的人际圈子继续咨询(家人的朋友、朋友的朋友),称为二度关系。当然希望找到关系最近的芒果商呀!也就是说,广度优先搜索不仅查找从A到B的路径,而且找到的是最短路径。
    • 注意:只有按添加顺序查找时,才能实现这样的目的。
    • 注意:避免重复问询,存在家人的朋友朋友的朋友是同一人情况!避免无限循环呀!
  • 实现:散列表,能够将键映射到值!散列表是无序的!
  • 运行时间:O(V+E);(V:节点数;E:边数)

11 数据结构:队列

  • 思想:以站台排队上车为例,站在前面的先上车。先上车的人将先离开等待的队列,并先被检查(检查健康码?)!
  • 操作:入队和出队
  • 性质:先进先出,不能随机地访问队列中的元素!

12 图算法:狄克斯特拉算法

  • 加权图:在图的基础上,提高或降低某些边的权重。
  • 思考:广度优先搜索,找出的是段数最少的路径,是不是最快的路径呢?新算法狄克斯特拉算法!找出总权重最小的路径!
  • 思想:以起点-终点为例,期间有不同的路线,即加权图。
    • 首先,找出"最便宜"的节点,即可在最短时间到达的节点。
    • 其次,更新该节点的邻居开销。
    • 然后,重复这个过程,直到对图中的每个节点都这样做了。
    • 最后,计算最终路径。
  • 注意:狄克斯特拉算法,只适用于有向无环图(环就是图上有圈圈);也不适用于含负权边的加权图(贝尔曼-福德算法)。

13 算法:贪婪算法

  • 思想:每步都采取最优的做法,就是选择局部最优解,最终得到全局最优解。
  • 案例:广度优先搜索;狄克斯特拉算法。
  • 注意:贪婪算法不一定获得最优解,但是执行简单,且能得到的结果与正确结果相当接近。
  • NP完全问题:最佳做法是使用近似算法。

14 算法:动态规划算法

  • 思想:先解决子问题,再逐步解决大问题。当且仅当每个子问题都是离散的,即不依赖于其他子问题。
  • 思考:
    • 动态规划可以帮助你在给定约束条件下找到最优解。
    • 在问题分解为彼此独立且离散的子问题时,可以使用动态规划来解决。
    • 每种动态规划解决方案都涉及网格!单元格中的值通常就是你要优化的值。

15 算法:K最邻近算法

  • 思想:以判断水果为例,现在有红柚和苹果两种类别,现有一个水果,判断它是柚子还是苹果?依旧最邻近特征进行判断!
  • KNN用于分类和回归,需要考虑最近的邻居。
  • 分类就是编组;回归就是预测数字。
  • 特征提取意味着将物品转换成一系列可比较的数字。

后言:书中的案例图文结合,推荐看书本案例,理解更优,最后一章节,概述了本书未提及的10种算法,后续可做进一步扩展阅读!包括:树、反向索引、傅立叶变换、并行算法、MapReduce、布隆过滤器和HyperLogLog、SHA算法、局部敏感的散列算法、Diffie-Hellman密钥交换和线性规划!

  • 14
    点赞
  • 10
    收藏
  • 打赏
    打赏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:黑客帝国 设计师:我叫白小胖 返回首页
评论 14

打赏作者

MengYa_DreamZ

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值