第一章笔记:基础知识

摘要:1.计算领域的核心理念2.渐进记法3.图与树的实现4.提防黑盒子

1.计算领域的核心理念

算法---一个执行过程,包含了能够解决某个特定问题的有限步骤集。(图灵机可以理解为是这个待解决问题的正规描述形式)

图灵机---计算领域的理论核心,图灵机有着各种不同的具体实现,但每种实现都可以看做一个有限状态机:由一个有限的状态集(包括已完成部分)与各种用于触发读写操作及不同状态切换的潜在符号共同组成。(可以将其看做机器运行所需的规则)。

随机存取机---适用于更细粒度上的算法分析,从标准单处理器计算机中简化出的一种抽象模型,好比有一块可以直接存取的内存,而不是同图灵机那样的可滚动的纸带。

   应具备的属性:

  • 没有任何形式的并发执行,只有在执行完一条指令后才能执行其他指令。
  • 所有标准基本操作,如算术运算 比较运算 以及内存存取,所耗费的时间都是常数级的,且没有更复杂的基本操作 如排序。
  • 计算机字尽管有限,但必须足够大,大到能满足我们在解决问题中所有内存编址的需求,此外还要有一定的额外变量。

问题---就目标而言,问题实际就是输入与输出之间的某种关系,更精确的讲,就是指一组集合对之间的数学意义上的关系,并且借由指定这种关系的过程,问题会被确定下来。

编码---对输入 0 1 编码,问题实例的大小,可以简单看成编码它所需的内存大小(通常与编码本身的确切属性没太大关系)。


2.渐进记法

append insert 的例子;

研究算法分析时要关注的重点:常数单位上的差距(通常取决于一些特定事物如通用编程语言的性能,硬件速度等);焦点 集中在那些能够独立于具体实现之外的属性。

2.1. 渐进记法是用于分析算法与数据结构的重要工具,核心思想为提供一种资源保护形式,主要用于分析某项功能在应对一定规模参数输入时所需要的资源(时间 内存 等)

渐进记法使用由希腊字母构成的记号体系。Ο记法代表渐进上界,Ω记法代表渐进下界,Θ记法代表前两种记法的交集。

2.2. 渐进记法 简化了我们面临的数学问题。

几种常用的渐进运行时间
时间复杂度 相关名称 相关示例及说明
Θ(1) 常数级 哈希表的查询与修改
Θ(lgn) 对数级 二分搜索
Θ(n) 线性级 列表遍历
Θ(nlgn) 线性对数级 任意值得最优化排序,其复杂度等同于Θ(lgn!)
Θ(n2) 平方级 拿n个对象进行相互比对
Θ(n3) 立方级 Floyd-Warshall算法
Ο(nk) 多项式级 基于n的k层嵌套循环(k为整数,k>0)
Ω(kn) 指数级 每n项产生一个子集(k>1)
Θ(n!) 阶乘级 对n个值执行全排列操作

多项式级与指数级分割着易处理问题和难处理问题,仅一般而言。

几条简单规则:加法运算中,只以阶数最高的被加数为准;乘法运算中,常数因子忽略不计;保持相关上下界的严谨性;Θ(f) + Θ(g) = Θ(f+g);Θ(f) * Θ(g) = Θ(f*g)。

三种重要情况:1.最好情况(理想输入时的运行时间)2.最坏情况(所能给的最佳保证)3.平均情况(回避)

实证式算法评估:1.当没有把握时,就把可能的解决方案都试一遍。2.用timeit模块进行计时:

import timeit
timeit.timeit("x = 2 + 2")
$命令行环境调用
$ python -m timeit -s"omport mymodule as m" "m.myfunction()"

3.使用profiler找出瓶颈:给出关于执行时间都都花在哪里的详细信息,从而确定代码中需要优化的部分。当主函数是main()时,执行下列代码,可以给出各个函数的运行时间。(可以使用Python Call Graph 工具可视化的看到代码的调用情况)

import cProfile
cProfile.run('main()')

4.绘制出结果。matplotlib绘制工具包

5.根据计时比对结果做出判断

6.通过相关实验对渐进时间做出判断


3.图Graph与树Tree的实现

图结构可以用来表现似乎所有类型的结构与系统,而树结构只是图结构的一种特殊情况但相当普遍。如果我们的问题可以用树结构来描述时,基本上已经有了有效的解决方案。

从七桥问题开始:全面介绍图论   https://www.jiqizhixin.com/articles/2018-03-11-2   (https://medium.freecodecamp.org/i-dont-understand-graph-theory-1c96572a1401)

数据结构与算法 图论    https://zhuanlan.zhihu.com/p/25498681

入门图论与网络分析 含python代码     https://www.jiqizhixin.com/articles/2018-08-07-16

3.1邻接列表

#简单明了的邻接集表示方法
a,b,c,d,e,f,g,h = range(8)
N = [
        {b,c,d,e,f},  #a
        {c,e},         #b
        {d},           #c
        {e},           #d
        {f},            #e
        {c,g,h},      #f
        {f,h},         #g
        {f,g},         #h
       ] 
>>>b in N[a]
True
>>>len(N[f])
3   

如果某些代码存在于某个源文件里,而我们又想在交互解释其中研究的话,使用python的 - i 开关来运行:

python -i listing.py 

#其他表示方法

#邻接列表   成员检测时速度放缓
a,b,c,d,e,f,g,h = range(8)
N = [
        [b,c,d,e,f],  #a
        [c,e],         #b
        [d],           #c
        [e],           #d
        [f],            #e
        [c,g,h],      #f
        [f,h],         #g
        [f,g],         #h
       ] 
#加权邻接字典
a,b,c,d,e,f,g,h = range(8)
N = [
        {b:2,c:1,d:3,e:9,f:4],  #a
        {c:4,e:3},                  #b
        {d:5},                       #c
        {e:1},                       #d
        {f:2},                       #e
        {c:5,g:6,h:7},           #f
        {f:2,h:6},                 #g
        {f:3,g:4},                #h
       ] 
#邻接集的字典表示法  类似字符类的邻接列表(成本略低)
a,b,c,d,e,f,g,h = range(8)
N = {
       'a': set('bcdef'),   #a
       'b': set('ce'),        #b
       'c': set('d'),          #c
       'd': set('e'),          #d
       'e': set('f'),           #e
       'f': set('cgh'),        #f
       'g': set('fh'),         #g
       'h': set('fg'),         #h
       }
#一个图的最佳表示法  取决于 我们要用它做什么

3.2邻接矩阵

节点编号从0 到V-1,用0 和1 来充当真值(无权图中),对角线上的值全为0 ,在无向图邻接矩阵关于对角线对称相等,

#用嵌套list实现的邻接矩阵
a,b,c,d,e,f,g,h = range(8)
N = [
        [0,1,1,1,1,1,0,0],          #a
        [0,0,1,0,1,0,0,0],          #b
        [0,0,0,1,0,0,0,0],          #c
        [0,0,0,0,1,0,0,0],          #d
        [0,0,0,0,0,1,0,0],          #e
        [0,0,1,0,0,1,0,0],          #f
        [0,0,0,0,0,1,0,1],          #g
        [0,0,0,0,0,1,1,0],          #h
       ] 
#可以更改不同的权值
#非法的权值就设置为极大值, float('inf')
inf = float('inf')  #权值为 inf

3.3树的实现

树本身就是图的特殊情况,但许多特定问题用特定的树结构更容易实现。

#简单的树结构 表示为二叉列表
>>>T = [["a","b"],["c"],["d",["e","f"]]]
>>>T[0][1]
'b'
>>>T[2][1][0]
'e'

#二叉树类
class Tree:
    def __init__(self,left,right):
        self.left = left
        self.right = right
>>>t = Tree(Tree("a","b"),Tree("c","d"))
>>>t.right.left
'c'

#多路搜索类
class Tree:
    def __init__(self,kids,next=None):
        self.kids = self.val = kids
        self.next = next
>>>t = Tree(Tree("a"),Tree("b",Tree("c",Tree("d")))))
>>>t.kids.next.next.val
'c'

参考:Bunch模式  https://www.cnblogs.com/GF66/p/9785485.html

3.4存在多种表示法

空泛的判断句子没有,我们更应该针对具体问题思考该任务的渐进性能。  

最主要的为以上介绍的两种。另外,需注意编程中没有注意就用到的图实现(隐式)

参考:图结构库

python-graph : https://github.com/pmatiello/python-graph

Graph-tool : https://graph-tool.skewed.de/

此外还有 Pygr 基于图结构的数据库 Gato基于图结构的动画工具箱 PADS基于图结构的算法集


4.提防黑箱子

编程时,我们必须依赖一些并不是自己编写的组件,称为黑箱子。不注意的话,Python和机器本身的很多机制会成为我们的绊脚石。

  • 当性能成为重要问题时,要注重分析实际而不是相信直觉
  • 当正确性至关重要时,最好用不同的实现方法核实答案

4.1隐性平方级操作

4.2浮点运算的麻烦


5.小结

基础概念,渐进记法与图结构,黑箱子......

加油 嘿嘿嘿!

猜你喜欢

转载自www.cnblogs.com/vangaohao/p/11342207.html