《算法图解》读书笔记

《算法图解》读书笔记  这是一本用来入门数据结构和算法的一本有趣的书

书中有关于这些算法实现的简单python代码,通俗易懂,适合新手阅读!

以下是我阅读后,根据书中的内容和顺序归纳的重要的知识点

  • 算法图解

    • 1、算法简介

      • 算法是一组完成任务的指令

      • 二分查找

        • 一般来说,对于n个元素的列表,用二分查找最多需要log2n步,而简单查找最多需要n步
          • 二分查找的速度比简单查找快得多
        • 仅当列表是有序的时候,二分查找才有用
      • 大O表示法O(n)

        • 指出了算法的速度有多块/算法运行时间的增速
          • 指出了最糟情况下的运行时间
        • O(log n) 对数时间---二分查找
        • O(n)线性时间---简单查找
          • 最多需要猜测的次数与列表的长度相同时,这种称为线性时间
        • O(n*log n)---快速排序(一种速度较快的排序算法)
        • O(n2)(n的平方)选择排序(一种速度较慢的排序算法)
        • O(n!)阶乘时间---旅行商问题的解决方案(一种非常慢的算法)
      • 算法的速度

        • 算法的速度指的并非时间(因此不以秒为单位),而是操作数的增数
        • 说的是随着输入的增加,其运行时间将以什么样的速度增加
          • 从增速的角度度量的
        • 算法的运行时间用大O表示法表示
        • O(log n)比O(n)快,当需要搜索的元素越多时,前者比后者快得越多
    • 2、选择排序

      • 存储元素的两种基本方式

        • 数组

          • 所有代办事项在内存中是相连的(紧靠在一起的)
          • 优点:需要随机地读取元素时,效率很高,可以迅速的找到数组的任何元素---随机访问
          • 在同一个数组中,所有元素的类型必须相同(都为int,double等)
          • 缺点:数据少时,会浪费内存;数据多时,会内存溢出
          • 读取时间:O(1) ; 插入/删除时间:O(n)
        • 链表

          • 可以存储在内存的任何地方(分开的)
            • 链表的每个元素都存储了下一个元素的地址,从而使一系列随机的内存地址串在一起
          • 优点:添加元素时,不需要移动元素,只需将其放入内存,并将其地址存储到前一个元素中
          • 缺点:若要查找一个特定元素,需要遍历前n个元素,效率低---顺序访问
          • 读取时间O(n);插入/删除时间O(n)
        • 术语

          • 数组的元素带编号,编号从0开始
          • O(n2)(n的平方)---排序算法
            • 将元素按顺序排列,每次遍历所有元素,依此找出符合条件的元素并排序
    • 3、递归

      • 让解决方案更清晰,并没有性能上的优势

        • 循环---程序的性能更高 ;递归---程序更容易理解
      • 每个递归函数都由两部分组成

        • 递归是指调用自己的函数
        • 基线条件(base case)
          • 函数不再调用自己,避免形成无限循环
        • 递归条件(recursive case)
          • 函数调用自己
        • 调用另一个函数时,当前函数暂停并处于未完成的状态
        • 用于存储多个函数的变量,称为调用栈
          • 所有函数调用都进入调用栈
        • 两种操作:压入和弹出
      • 递归调用栈

        • 在一个函数调用中不能访问另一个的x变量
        • 存储详尽的信息可能占用大量的内存
          • 解决占用大量内存的方法
            • 重新编写代码,转而使用循环
            • 使用尾递归
              • 并非所有语言都支持尾递归
    • 4、分而治之(D&C)

      • 一种著名的递归式问题解决方法

      • D&C解决问题的两个步骤

        • (1)找出基线条件,这种条件必须尽可能简单
        • (2)不断将问题分解(或者说缩小规模),直到符合基线条件
          • 递归条件——缩小问题规模
        • 基线条件很可能是空数组或只包含一个元素的数组
      • 快速排序

        • 基线条件是数组为空或只包含一个元素
        • 步骤
          • (1)从数组中选择一个元素,这个元素被称为基准值(pivot)
          • (2)分区(partitioning):将数组分为两个子数组:小于基准值的元素和大于基准值的元素
          • (3)将这两个子数组进行快速排序
        • 归纳证明——证明算法行之有效的方式
          • 基线条件
          • 归纳条件
        • 排序速度取决于选择的基准值
          • 平均运行时间O(n logn)
            • 最糟情况下的运行时间是O(n2)(n的平方)
          • 合并排序
            • 运行时间O(n logn)
          • 若两种算法的大O运行时间不同,常量将无关紧要;若运行时间相同,那么常量将影响很大
            • 由于快速查找与合并查找的运行时间都为O(n logn),而快速查找的常量比合并查找小,则快速查找的速度将更快
        • 最糟情况和最佳情况
          • 最糟情况
            • 层数O(n)*每层需要的运行时间O(n)=O(n2)(n的平方)
          • 最佳情况/平均情况
            • 层数O(log n)*每层需要的运行时间O(n)=O(n logn)
    • 5、散列表

      • 也称为散列映射、映射、字典和关联数组

        • 结合散列函数和数组来创建散列表
      • 散列函数

        • 将同样的输入映射到相同的索引
        • 将不同的输入映射到不同的索引
        • 散列函数知道数组有多大,只返回有效的索引
        • 用来确定元素的存储位置
      • 应用

        • 将散列表用于查找/模拟映射关系
          • python中用dict来创建字典,包含键和值
            • 将网址映射到IP地址——DNS解析
            • A=dict{ }
        • 防止重复
        • 将散列表用作缓存/记住数据
          • eg.Web服务器上
      • 冲突

        • 将两个键分配到了相同的位置
        • 解决方法:在该位置存储一个链表
          • 若散列表存储的链表很长,散列表的速度将急剧下降
        • 避免方法
          • 较低的填装因子
            • 填装因子:散列表包含的元素数/位置总数
            • 填装因子大于1时,意味着填装的元素数>数组的位置数
              • 需要在列表中添加位置——调整长度
            • 填装因子越低,发生冲突的可能性越小,散列表性能越高
            • 通常,一旦填装因子>0.7,就调整散列表的长度
          • 良好的散列函数
            • 让数组中的值呈均匀分布
      • 性能

        • 平均情况
          • 执行各操作的时间都为O(1)常量时间
        • 最糟情况
          • 执行各操作的时间都是O(n)
      • 散列表是无序的,因此添加键值对的顺序无关紧要

    • 6、广度优先搜索

      • 用于图的查找算法

        • 从A出发,有前往B的路径吗?(且找出的就是最短路径)
        • 从A出发,前往B的哪条路径最短?
        • 由节点和边组成
          • 邻居:与某节点相连的众多节点
        • 有向图
          • 边为箭头,箭头的方向指定了关系的方向
        • 无向图
          • 边不带箭头,其中的关系是双向的
      • 队列

        • 一种先进先出( FIFO )的数据结构
        • 栈:先进后出( LIFO )的数据结构,常用于函数调用
      • 运行时间:O(V+E),V为顶点数,E为边数

      • 面临类似于寻找最短路径的问题时,可尝试使用图来建立模型,再使用广度优先搜索来解决问题
        • 找到的是段数最少的路径
      • 按加入的顺序检查搜索列表中的元素,否则就不是最短路径,因此搜索列表必须是队列
        • 对于检查过的元素,务必不要再去检查,否则可能陷入无限循环
    • 7、狄克斯特拉算法

      • 找出最快的路径——即找出有权图的中总权重最小的路径
        • 最短路径指的并不一定是物理距离,也可能是让某种度量指标最小
      • 步骤

        • (1)找“最便宜”的节点,即可在最短时间内到达的节点
          • 散列表
        • (2)更新该节点的邻居的开销
          • 嵌套散列表
        • (3)重复以上过程,直到对图中的每个节点都这样做了
          • 循环
        • (4)计算最终路径
      • 术语

        • 加权图
          • 用狄克斯特拉算法
            • 若有负权边,就不能用狄克斯特拉算法,可以用 贝尔曼-福德算法
        • 非加权图
          • 用广度优先搜索
    • 8、贪婪算法

      • 每步都选择局部最优解,最终得到的就是全局最优解
        • 贪婪算法易于实现、运行速度快,是不错的近似算法
      • 集合类似于列表,不能包含重复的元素
        • python中: | 并集 ;& 交集 ;- 差集
      • NP完全问题

        • 以难解著称的问题
          • 还没有找到快速解决方案
          • 最佳的做法是使用近似算法
        • 判断是否是NP完全问题
          • 涉及“所有组合”的问题通常是NP完全问题
          • 不能将问题分成小问题,必须考虑各种可能的情况,可能是NP完全问题
          • 涉及序列(如旅行商问题中的城市序列)且难以解决,可能是NP完全问题
          • 涉及集合(如广播站集合)且难以解决,可能是NP完全问题
          • 若问题可转换为集合覆盖问题或旅行商问题,那么它肯定是NP完全问题
    • 9、动态规划

      • 在给定约束条件下优化某种指标时很有用

        • 先解决子问题,再逐步解决大问题
      • 当且仅当每个子问题都是离散的,即不依赖于其它子问题时,动态规划才管用

      • 每种动态规划解决方案都涉及网格
        • 单元格中的值通常就是要优化的值
          • 将某个指标最大化
            • 最长公共子串
            • 最长公共子序列
        • 每个单元格都是一个子问题,因此需要考虑如何将问题分成子问题,然后来找出网格的坐标轴
      • 应用

        • 生物学家依据最长公共子序列来确定DNA链的相似性,进而判断两种动物或疾病有多相似;寻找多发性硬化症治疗方案
        • git diff 等命令,用来指出两个文件的差异
        • 编辑距离(levenshtein distance)指出两个字符串的相似程度。用途有:拼写检查,判断用户上传的资料是否是盗版
        • Microsoft Word等具有断字功能的应用程序,确定在什么地方断字以确保行长一致
      • 没有放之四海皆准的计算动态规划解决方案的公式

    • 10、K最近邻算法KNN

      • 机器学习

        • OCR(光学字符识别)
          • 拍摄印刷页面的照片,计算机将自动识别出其中的文字
          • 识别步骤
            • 浏览大量的数字图像,将数字特征提取出来
              • 训练(training)
            • 遇到新图像时,提取该图像的特征,再找出最近的邻居
        • 创建垃圾邮件过滤器
          • 使用朴素贝叶斯分类器
      • 度量两个对象有多相似

        • 距离公式
        • 余弦相似度
      • 两项基本工作

        • 分类
          • 分类就是编组
        • 回归
          • 回归就是预测结果
        • 挑选合适的特征很重要
          • 特征抽取意味着将物品转换为一系列可比较的数字
            • 能否挑选到合适的特征事关KNN算法的成败
      • KNN用于分类和回归,需考虑最近的邻居
      • 11、接下来怎么做

          • 二叉查找树

            • 查找/插入/删除 的平均运行时间均为O(logn) 查找时最糟的情况下的平均时间复杂度是O(n)
          • 数组

            • 查找O(logn) 插入/删除O(n)
          • 其它平衡的树

            • B树
              • 数据库常用它来存储数据
            • 红黑树
            • 伸展树
        • 反向索引

          • 创建搜索引擎:通过一些关键字,返回用户想访问的页面
        • 傅里叶变换

          • 非常适用于处理信号
            • 压缩音乐
            • 地震预测
            • DNA分析
        • 并行算法

          • 为提高算法的速度,需要让它们能在多个内核中并行地执行
          • 对数组进行排序时,快速排序的并行版本所需的时间是O(n)
          • 即使给电脑装备两个内核,算法的速度也不可能提高一倍
            • 并行性管理开销
              • 将两个数组合并成一个数组,也需要时间
            • 负载均衡
        • 分布式算法

          • MapReduce

            • 可以用开源工具Apache Hadoop来使用
            • 基于两个理念
              • 映射(map)函数
                • 将一个数组转换为另一个数组
              • 归并(reduce)函数
                • 将一个数组转换为一个元素
            • 数据集很大,包含数十亿行时,使用MapReduce只需几分钟就可获得查询结果
          • 分布式算法适用于在短时间内完成海量的工作
        • 布隆过滤器和HyperLogLog

          • 布隆过滤器

            • 一种概率型数据结构,它提供的答案有可能不对,但可能是正确的
              • 可能出现错报的情况
              • 不可能出现漏报的情况
            • 优点在于占用的存储空间很少
            • 非常适用于不要求答案绝对准确的情况
          • HyperLogLog

            • 近似地计算集合中不同的元素数,不能给出准确的答案,但也八九不离十,而占用的内存空间少很多
          • 面临海量数据且只要求答案八九不离十时,可考虑使用概率型算法
        • SHA算法

          • 散列函数用来确定应将这个值放在数组的什么地方
            • 查找时间是固定的O(1)
          • 另一种散列函数:安全散列算法(SHA)函数

            • 给定一个字符串,SHA返回其散列值——一个较短的字符串
            • 用于创建散列表的散列函数接受一个字符串,并返回一个数组索引号
            • SHA根据字符串生成另一个字符串
            • 应用
              • 判断两个文件是否相同
                • 在超大型文件时很有用
                  • 计算它们的SHA散列值,再对结果进行比较
              • 检查密码
                • SHA被广泛应用于计算密码的散列值,这种散列算法是单向的——可以根据字符串计算出散列值,无法根据散列值推断出原始字符串
              • 要使用SSHA算法来计算密码的散列值,用SHA-2和SHA-3
            • SHA实际上是一系列算法:SHA-0、SHA-1、SHA-2和SHA-3
            • 最安全的密码散列函数是bcrypt,但没有任何东西是万无一失的
            • 重要特征:局部不敏感
              • 若修改其中的一个字符,再计算其散列值,结果将截然不同
                • 让攻击者无法通过比较散列值是否类似来破解密码
            • 局部敏感的散列函数

              • Simhash
                • 对字符串做细微修改,生成的散列值只存在细微的差别
                  • 能够比较散列值来判断两个字符串的相似程度
        • Diffie-Hellman密钥交换

          • 解决了
            • 双方无需知道加密算法,即不必会面协商要使用的加密算法
            • 要破解加密的消息比登天还难
          • 使用两个密钥

            • 公钥
              • 公开的,可将其发布到网站上,通过电子邮件发送给朋友,或其它任何方式来发布
            • 私钥
              • 要发布消息时,用公钥进行加密,加密后的消息只有使用私钥才能解密
        • 线性规划

          • 在给定约束条件下最大限度地改善指定的指标
            • 线性规划使用Simplex算法
          • 所有图算法都可使用线性规划来实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值