数据结构与算法(python)第一章绪论

1.1 计算机问题求解
开发出能解决问题的程序
1.1.1 程序的开发过程
1:分析阶段(需求分析)
2:设计阶段
3:编码阶段
4:检查测试阶段
5:测试/调试过程
1.1.2一个简单示例
对数字开平方根,算法设计与分析
1:给定x和允许误差e,令变量y取任意正实数值,如令y=x;
2:如果|yy-x|<e,计算结束并返回y的值;
3:取z=(y+x/y)/2;
4:将z作为y的值返回步骤2;
1.2 问题求解:交叉路口红绿灯安排
安全问题,经济问题
1.2.1 问题分析和严格化
其中一种数据结构:图
图中元素成为顶点,连接线成为边或者弧,相互之间有边的顶点称为邻接顶点。
1.2.2 图的顶点分组和算法
枚举和选择(选优法):顶点分组,枚举出所有可能,但代价太高,效率低下。
贪婪算法(贪心法)
1.2.3 算法的精化和python描述
1.2.4 讨论
仍有很多不足
小结
1.3 算法和算法分析
1.3.1 问题,问题实例和算法
三个基本概念:问题,问题实例,算法
算法的性质:有穷性,能行性,确定性,终止性,输入/输出
满足确定性的算法称为确定性算法 ,实际上人们现在更加关注 非确定性算法,如并行算法,概率算法等
算法的描述
采用自然语言描述
采用在自然语言描述中结合一些数学记法或公式的描述形式
采用严格定义的形式化记法描述形式(采用某种通用的计算机模型描述 方式,采用某种严格的专门为描述算法而定义的形式化描述语言)
采用类似某种编程语言的形式描述算法(常用)
采用某种伪代码的形式(常用)
算法和程序
程序可以看作采用计算装置能够处理的语言描述的算法,称为算法的实现
程序可以采用各种计算机语言描述,不同语言描述的算法运行效率也是不同的
算法设计与分析
算法设计中常见的通用想法可以称为算法设计模式
主要有:
枚举法
贪心法
分治法
回溯法
动态规划法
分支限界法
很多复杂的算法一般都是多种算法模式结合
算法的共有性质中,最重要的就是算法的实施都需要耗费资源,即一个算法 的实施必定都蕴含着一定量的时间和空间开销
算法分析的主要任务就是弄清算法的资源消耗
算法分析最重要的作用是作为评价算法的一种标准
1.3.2 算法的代价及其度量
代价包括:
所需的储存空间
所需的求解时间
存储占用的最高位限
度量的单位和方法
以问题实例的某种规模n为参量,反映出这个算法在处理规模为n的问题实例时需要付出的时间(或者空间)的代价
在规模n趋向于无穷的过程中,有关函数的增长速度
这两个函数关系称为算法的时间代价空间代价
与实例和规模有关的两个问题
first:分析有关算法时采用的尺度不同,算法的代价也不同
判断素数的问题中,有两个尺度可能作为实例的规模度量,一种可能是用被检查的数值,另一种可能是取被检查整数按某种进制表示的数字串长度
second:对同样规模的实例,计算代价也有可能不同
判断素数的问题中,同样由100个10进制数字表示的数,如果是偶数,则只需要一次判断,而奇数则是需要花费更多时间
度量算法的三种考虑:
最少时间:价值不大
最多时间最坏情况的时间代价
平均时间:一方面完整全面的反映了这个算法的性质,另一方面这个时间代价并无保证,不是每个实例都在这个平均时间内完成的,且现实中常常难以确定平均代价。
常数因子和算法复杂度
对于算法的时间和空间中,最重要的是量级趋势,这是代价的主要部分
代价函数的常量因子可以忽略不记:3n和100n属于同一个量级
大O记法
对于单调的整数函数f,如果存在一个整数函数g和实常数c>0,使得对于充分大的n总有f(n)<=c
g(n),就说函数g是f的一个渐近函数,记为f(n)=Og(n),说明在趋向无穷的意义下,函数f的增长速度受到函数g的约束
把上述描述方法应用于算法的代价问题,假设存在函数g,使得算法A处理规模为n的问题实例所用的时间T(n)=O(g(n)),则称O(g(n))为算法A的渐近时间复杂度,简称时间复杂度,算法的空间复杂度的定义与此类似。
O(1):常量复杂度
O(logn):对数复杂度
O(n):线性复杂度
O(n*n):平方复杂度
O(2*n):指数复杂度
算法复杂度的意义
算法的复杂度决定了算法的可用性
算法复杂度由空间复杂度与时间复杂度决定
1.3.3 算法分析
算法分析的目的是推导出算法的复杂度
其主要的技术是构造和求解递归方程
基本循环程序
如只考虑算法的时间复杂度,其中只有顺序结构,条件分支,循环结构:
1:基本操作,认为其时间复杂度为O(I),如果是函数调用,应该将其时间复杂度代入,参与整体时间复杂度是计算。
2:加法规则(顺序复合):如果算法是两个部分的顺序复合,其复杂性是两个部分的复杂性之和,由于忽略了常量因子,加法等价于求最大值,取两个中复杂度较大的一个。
3:乘法规则(循环结构):如果算法是一个循环,循环体将执行T(n)次,每次需要的时间为S(n)。
4:取最大规则(分支结构):如果算法是条件分支,两个分支的时间复杂性分别为T(n)和S(n),则复杂度为其中较大一个
递归算法的复杂度

def re(n):
	if n==0:
		return g(...)
		somework
		for i in range(a)
			x=re(n/b)
			somework
		somework

T(n)=O(n的k次方)+a*T(n/b)
结论:
如果a>b的k次方,那么T(n)=O(n的log以b为底a为对数的次方)
如果a=b的k次方,那么T(n)=O(n的k次方*logn)
如果a<b的k次方,那么T(n)=O(n的k次方)
1.3.4 python程序的计算代价(复杂度)
时间开销
基本算术运算符是常量时间操作
逻辑运算符是常量时间运算
组合对象中:
复制和切片操作通常需要线性时,list和tuple的元素访问和元素赋值是常量时间,dict操作中情况比较复杂
字符串也应看作组合对象,其许多操作不是常量时间的
创建对象也需要付出空间和时间,空间和时间代价都与对象的大小有关,对于组合对象,需要构造一个个元素,元素又有大小问题,整体要看元素的个数,看作是线性时间和线性空间
构造新结构,如构造list,set等,构造空结构是常量时间操作,构造一个包含n个元素的结构,则至少需要O(n)时间
字典dict操作效率,主要操作是加入新的关键码-值对和基于关键码查找关联值,最坏的情况是O(n),平均复杂度是O(1),另外在表的最后插入和删除元素的操作效率最高,在其他地方加入和删除元素的效率最低,应优先考虑前者。
空间开销
建立一个表或者元组,至少要占用元素个数那么多的空间,如果一个表的元素个数与问题规模线性相关,建立它的空间付出至少为O(1)(如果元素也是新创建的,还需要考虑元素本身的存储开销)
python中各种组合数据对象都没有设定最大元素个数,在实际中,根据元素个数的增加自动扩充存储空间,从空间占用 的角度看,实际存储开销可能变大,但不会自动缩小,即便将其中的元素删除,也不会变化。
python中自动存储管理系统的影响,全局变量会一直占用存储空间,除非是作为局部变量或者在后来通过赋值将其抛弃,这个表的对象就可以被收回。
python程序的时间复杂度实例
程序实现和效率陷阱
从全局与局部来看是不同的
1.4 数据结构
1.4.1 数据结构及其分类
信息,数据和数据结构
信息
数据就是经过编码的信息
数据元素:最基本的是二进制位
数据结构:研究数据之间的关联和组合形式
抽象定义与重要类别
典型数据结构:
集合结构
序列结构也称线性结构,有简单序列结构,环形结构和p形结构等,
层次结构其数据元素分属于一些不同层次,一个上层元素可以关联着一个或者多个下层元素。
树形结构只有一个最上层的数据元素称为
图结构数据元素之间有任意复杂的相互联系
算法和程序中的数据结构
结构性和功能性的数据结构
1.4.2 计算机内存对象表示
内存单元和地址
内存储器(内存):
计算中直接使用的数据保存在内存中
内存是CPU可以直接访问的数据存储设备。
外存:
如光盘,磁盘,磁带等
保存在外存的数据必须先装入内存,CPU才能访问它
内存的基本结构:是一批线性排列的存储单元,每个单元大小相同,通常一个单元可以保存一个字节(8位二进制代码)的数据。
内存单元具有唯一编号,称为
单元地址(地址)

对象存储和管理
内存区域是指地址连续排列的一个或者多个单元
python中标准函数id取得对象的标识
对象的访问 **
直接通过标识访问是常量时间
对象关联的表示
顺序表示
链接表示通过链接形成的复杂结构称为链接结构
1.4.3 python对象和数据结构
python中,在变量里保存值(对象)的引用的这种实现方式称为变量的
引用语义**
有些语言(如C语言)中则是把变量的值直接保存在变量的存储区里,称为值语义
python对象的表示
python语言的实现基于一套链接结构 ,变量与其值对象的关联通过链接的方式实现,对象之间的联系也通过链接,一个复杂对象的内部也可能包含多个子部分,相互之间也是通过链接建立联系。
python的几个标准数据类型
list(表)
tuple(元组)构造之后不可变
dict(字典)关键码只能是不变对象(例如,可以是字符串,元组,但不可以是表),如果关键码是组合对象,那么其元素仍然是不变对象,支持高效(常量时间)检索

猜你喜欢

转载自blog.csdn.net/weixin_45955630/article/details/105877219