- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议83:努力降低算法复杂度
同一问题可用不同算法解决,而一个算法的优劣将直接影响程序的效率和性能。算法的评价主要从时间复杂度和空间复杂度来考虑。空间复杂度的分析相对来说要简单,并且在当前的计算硬件资源发展形势下,对空间复杂度的关注远没有时间复杂度高。因此降低算法的复杂度主要集中在对其时间复杂度的考量,本章侧重考虑时间复杂度。算法的时间复杂度是指算法需要消耗的时间资源,常使用大写字母O表示。如插入排序的时间复杂度为O(n2),快速排序的最坏运行时间是O(n2),但是平均运行时间则是O(n log n)。同一算法对应的不同代码实现的性能差异可能仅仅体现在其系数上,但数量级上仍然在同一水平,但不同时间复杂度的算法随着计算规模的扩大带来的性能差别则较为明显。下面是算法时间复杂度大O的排序比较:
O(1)<O(log* n)<O(n)<O(n log n)<O(n 2)<O(c n)<O(n!)<O(n n)
因此对算法改进的目的是尽量往时间复杂度较低的O靠近。要降低算法的复杂度,首先要对算法复杂度进行分析。算法分析建立在一定的假设前提上:即一台给定的计算机执行每一条指令的时间是确定的,因此,对于获取字典中某个key对应的值,其时间复杂度为O(1),查找列表中某个元素,其时间复杂度最优为O(1),最坏的情况为O(n)。下面的示例中用于求两个列表交集,即使函数中存在条件分支,虽然if部分运算的时间复杂度为O(1),但else部分需要循环遍历两个列表,其时间复杂度为O(n2),因此最终的算法复杂度为O(n2)。
def intersection1(list1,list2): result = {} if len(list1)<5: # 时间复杂度为O(1) print list1 else: # 时间复杂度为O(n2) for item in list1: if item in list2: result[item] = True return result.keys()
需要特别说明,算法的复杂度分析的粒度非常重要,其前提一定是粒度相同的指令执行时间近似,千万不能将任意一行代码直接当做O(1)进行分析。例如上面的例子中如果有其他函数再调用intersection1,纵然在调用函数中只有一行代码,该行代码的时间复杂度仍然要按照O(n2)计算。另外,算法复杂度分析建立在同一级别语言实现的基础上,如果Python代码中含有C实现的代码,千万不能将两者混在一起进行评估。关于更多算法分析的思想和方法,读者可以查看数据结构与算法相关资料。
Python常见数据结构基本操作的时间复杂度如表8-4所示。
表8-4 常见数据结构基本操作的时间复杂度
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论