Python 中 list 操作之 append、extend
先来一段代码:
这是非常常见的一种通过 append 方法逐个增加元素创建列表的场景,而且通常我们可以理解为上述代码的时间复杂度为 O(n)。这不能算错,但描述有点不准确,稍微理解 Python 列表类底层内容的小伙伴应该知道,列表类使用动态数组来存储数据。既然是动态数组就有动态调整数组大小的情况出现,在有些情况下数组容量大小调整耗时还是很可观的。有些资料为了描述准确,使用摊销的概念描述上述情况的时间复杂度,即上述代码行为在摊销情况下时间复杂度为 O(n)。关于摊销的概念可自行搜索相关资料,文章后面也会给出参考资料[1]供大家阅读。
所以我们应该尽量避免动态数组的频繁大小调整,对于上面的例子,当 n 已知并且较大时,更好的实现方法是使用列表推导,即
实验可以证明列表推导的语法比不断增添数据来建表的速度明显更快,原因是列表推导在构建输出时已经将要占用的数组大小计算完毕,减小了动态数组大小的扩大次数。
其实,如果 squares 仅仅作为一个中间变量,并且后序如有遍历的需要,更好的方法是使用生成器来处理,即:
关于生成器的讲解,请参考文章末尾链接。
类似的,在很多优秀的代码示例中经常看到,使用乘法操作初始化一张具有固定值、固定大小的列表,例如 ans=[None]*10,这也非常具有 Pythonic 风格。这样做不但语法简单,而且比逐步构造效率高。
有时候我们还面临这么一种场景,需要将两个列表合并。按照上面的分析,同样存在动态数组容量大小调整影响效率的可能。在实践中,相对于重复调用 append 方法,我们更倾向于使用 extend 方法。extend 效率的提升来源于更新列表的最终大小能够提前计算得到。假如需要追加的列表非常大,重复调用 append 方法时,底层动态数组会有多次调整大小的风险。若使用 extend 操作,最多执行一次调整动作。
注意,以下两种方式等效:
推荐阅读
参考书籍:
[1]. Data Structures and Algorithms in Python. ---Michael T. Goodrich
好好学习,天天向上!
版权声明: 本文为 InfoQ 作者【王坤祥】的原创文章。
原文链接:【http://xie.infoq.cn/article/a2ec24102843843a1519f6691】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论