《Python常用算法手册》笔记和读后感

这是一篇关于Python和常用算法结合的blog。
以下是之后笔记的目录

  1. 初步认识算法思想
  2. 枚举算法思想
  3. 递归算法思想
  4. 分治算法思想
  5. 贪心算法思想
  6. 回溯算法思想
  7. 迭代算法思想
  8. 查找算法
  9. 排序算法
  10. 使用算法解决数据结构问题
  11. 解决数学问题
  12. 经典算法问题
    那么今天愉快的算法分享时间就开始了

Day1
一:初步认识算法思想
1.1.1 什么是算法
为了使大家能够清晰的知道算法的定义。以后我对某一困难概念的解释就是从他的本质,加上一定的形容词副词之类的范围扩充,说白了讲就是扩句。我觉得这种方法可以让大家抓住信息的要点。那么话又扯回来,什么是算法?

  • 算法是指令。
  • 算法实质化来讲是解决问题的一系列有序的指令集合。
  • 算法虚化来讲是一种思想,一种解决问题的套路。
    我们将这个拆解开算法就是计算的方法,一种解题的思路,一种处理问题的思想。可以很抽象到无法诉说也可以很具体到一处代码。这就是我们要学的,其实是一种方法集合。

1.1.2 计算机中的算法分为两大类:数值类运算算法(求解数值)和非数值类运算算法(事务管理领域此处还没有具体例子暂时存疑)。而一般的算法解决的就是数值计算问题居多。

1.1.3 算法的基本五大特征

  1. 有穷性:步骤有限
  2. 确切性:步骤有明确的定义
  3. 输入:算法有0个或多个输入,初始化算法的基本情况。若是0输入则表示算法本身舍弃了初始条件。零输入的算法举例:
  4. 输出:每个算法有1个或是多个输出,没有输出就如同Python中缺少了print一样,无论你之前写了什么代码,解决了什么问题,没有计算机与人的交互我们什么也无法得到。
  5. 可行性:算法可以精准地进行有限次的运算。

1.2 算法是程序的灵魂
著名科学家沃思提出了以下的公式:

算法常用的python库 python常用算法手册_流程图

当然现实中我们采用结构化程序设计方法进行程序设计,并且用一种计算机语言来表示。因此也可以用下面的公式来表示程序:

算法常用的python库 python常用算法手册_数据结构_02

好了我们又遇到了新名词,结构化设计方法(structured programming,SP),讲结构化设计方法之前我们先将程序设计方法分类:面向结构的程序设计和面向对象的程序设计。而结构化程序设计就是面向结构,即把想要实现的功能,想要解决的问题,给模块化,就是不同的模块有不同的功能,而所有模块加起来就是问题的解决。这里扯开一下,一谈到程序设计,我们就会想到程序维护,所以如果我们想要程序维护时轻松一点,就应该把功能给分开模板化,这样下次想改什么功能就可以直接替换模块。举个简单的例子:我们用冒泡排序棑一个数组,并从小到大输出。那么我们是边排边输出还是排完了之后再输出,当然效率肯定是第一个快,但我们的第二种却是将排序和输出这两个功能分开为了两个没用干扰的模块,那么我下次有什么更快捷的排序方法就可以直接替换掉冒泡排序。这样就可以提升时间效率,方便我们进行后期的程序维护。那么这就是结构化程序设计的思想精髓。

那么什么是面向对象的程序设计呢?我们先来解释一下一个名词:封装。很好理解,我们原来结构化设计的时候,我们都会有初始的数据和要对其进行操作的函数等,那么封装就是将本来在结构化设计程序中分开的这两个东西给封装在了一起,形象一点就是把这两货用一个箱子套起来,形成一个类。这就防止了结构化程序设计中任何代码都可以改变数据的bug,当我们在查找bug的时候结构化程序设计会十分麻烦,什么代码都有可能有漏洞,而面向对象则简单,因为其强制程序必须通过函数的形式调用操纵数据。所以我们在编译阶段就可以进行改错。

数据结构可以去看我对《大话数据结构》的整理,程序设计方法也解决了,语言和环境就是对计算机操纵的一种指令和写指令并翻译运行的地方。对应到现实比如就是C语言和DEV C++。

1.3 算法的表示方式

  1. 用语言来描述
  2. 用流程图来表示(详细的流程图图像这里略)
    常见的三中流程图的结构:1)顺序结构;2)选择结构;3)循环结构
  3. 用N-S流程图来表示
    N-S流程图省略了流程线,将程序都写在一个大框中,详细见ns流程图

1.4 python的算法思想

1.4.1 常用的算法思想(也就是目录中的几个算法思想):

  1. 枚举算法思想:遍历所有结果找到合适的
  2. 递归算法思想:将大问题分解成同类的子问题,进一步分解为更小的问题,直到每一个小问题可以解决为止。
  3. 分治算法思想:将一个规模为N的问题分解成K个规模较小的子问题,这些子问题相互独立且与原问题性质相同,求出子问题的解就可以得到原问题的解。这里注意区分分治与约化(有兴趣的可以去了解NP问题约化到NPC问题)之间的区别,他们都是求最后那个问题的解即可解决原问题,不过分治是规模变小变简单,而约化则是归结为一个更难的问题,两者本质的思想都一样:将一个问题转化为另一个问题,再将转化的那个问题解决即可。
  4. 贪心算法思想:不从整体最右考虑,仅做出当前的最优选择,即局部最优解组成的解
  5. 回溯算法思想:为了求得问题的解,先选择某一种可能的情况进行试探,若在试探过程中,一旦发现原来的选择的假设情况是错误的,就退一步重新选择假设,并继续向前进行试探,如此反复进行,直到证明无解或得到解。说实话这个有点像我们那时候浙i江高考里面的证明题或是求范围的数学压轴题,我不知道你最后是什么结果,但我先找所有可能范围解中的一个范围进行探索,一旦证伪就舍弃,去另一个范围再探,直到得出最终范围。这个让我想起了曾经被数学压轴题的必要性探路支配的恐惧。
  6. 迭代算法思想:不断用变量的旧值推出新值的过程,通过对一组指令的重复运行,其旧值不断被新值所替代,直到推到答案。与递归的思想可逆,一个是从后推到前,一个是从前推到后。迭代效率比递归快,但递归能求解的问题迭代不一定解的了。

1.4.2 衡量算法优劣的标准
可见我在《大话数据结构》这一块的总结

1.4.3 算法复杂度(较之在《大话数据结构》中的分析有更进一步)
①时间频度
一个算法中语句的执行次数称为语句频度或是时间频度,记为T(n)。是具体的执行次数
②(渐进)时间复杂度
执行算法所需要的计算量。我的理解是计算量量级,是具体执行次数的简化处理。

比较:时间复杂度相同可能对应的时间频度不同。比如T(n)=n2+n与T(n)=3n2+1,而他们的时间复杂度都为O(n2)
③时间复杂度和空间复杂度的取舍问题
大多数情况下我们注重的都是时间复杂度,但我们不能一概而论说时间复杂度比空间复杂度重要,特定场景下不同,所以我们要在时间和空间的消耗上找一个平衡点即既能在损失可接受空间的情况下大幅度提高性能,又保证空间的损失不至于大到无法接受。这也是我们在一定程度上可以用空间来换取时间的原因。比如,你想查找0000到2000那些年份是闰年,你可以设置一个判断是否为闰年的程序进行判断,我也可以把0000和它是否为闰年的数据存储起来,到时候查询的时候一调用就出来了。但因为现在的兴情况是空间条件宽裕(硬件内的存储成本的降低),大家的空间优势差不多,使得我们拼的就是速度,谁的算法执行快,谁的产品用户体验好,谁就有优势。
1.11晚
Day 2
二:枚举算法
2.1 枚举算法基础
①枚举算法的需要条件:1)可以预先确定候选答案的数量;2)候选答案的范围在求解之前必须有一个确定的集合
速度慢但结果正确
②实现枚举算法
谈到枚举大家应该想到了遍历也就是循环的for或while+if
1)确定枚举对象、枚举范围和判定条件
2)逐一列举可能的解并验证是否为问题的解
要点:1)确定解的可能范围,不遗漏、不重复;2)使可能解的范围降至最小

2.2 具体的例子

--------未完待续--------