Python 高手编程系列三百九十三:简化

为了降低代码的复杂度,数据存储的方式是根本。你应该仔细选择你的数据结构。本
节提供了一些示例,说明如何针对任务,选择合适的数据类型以改善简单代码片段的性能。
在列表中搜索
由于 Python 中的 list 类型的实现细节,在列表中搜索特定的值并不是一个廉价的操
作。list.index()方法的复杂度是 O(n),其中 n 是列表元素的数量。如果不执行许多元
素的索引查找,这种线性复杂度不是特别糟糕,但如果需要许多这样的操作,它可能具有
负面的性能影响。
如果你需要在列表上快速搜索,你可以尝试 Python 标准库中的 bisect 模块。此模块
中的函数主要设计用于插入或查找给定值的插入索引,并且会保留有序序列的顺序。总之,
它们通过使用二分法算法可以有效地找到元素索引。这是该函数的官方文档中的配方,它
使用二分查找算法寻找元素索引:
def index(a, x):
‘Locate the leftmost value exactly equal to x’
i = bisect_left(a, x)
if i != len(a) and a[i] == x:
return i
raise ValueError
注意,bisect 模块中的每个函数都要求必须是有序序列才能正常工作。如果你的列
表不是正确的顺序,那么对它进行排序,这是一个至少有 O(nlogn)复杂度的任务。这比 O(n)
更糟糕,所以为了只执行一个单一的搜索就排序整个列表,这肯定入不敷出。然而,如果
你需要在一个巨大的列表中执行大量的索引搜索,并且这个列表不需要经常更改,那么使
用单个排序操作的 bisect 可能是一个很好的折衷。
此外,如果你的列表已经是有序的,则可以使用 bisect 将新元素插入到该列表中,
而无需重新排序。
使用集合而不是列表
当你需要从给定的序列中构建一系列不同的值时,你可能会想到的第一个算法是如下所示:

sequence = [‘a’, ‘a’, ‘b’, ‘c’, ‘c’, ‘d’]
result = []
for element in sequence:
… if element not in result:
… result.append(element)

result
[‘a’, ‘b’, ‘c’, ‘d’]
复杂度是通过使用 in 操作符在 result 列表中的查找引入,该操作的时间复杂度是 O(n)。
然后在循环中使用,这将花费 O(n)。因此,总体复杂度是平方—O(n2)。
做同样的工作,使用集合类型将更快,因为它使用与 dict 类型相同的哈希表来查找存
储的值。此外,集合确保元素的唯一性,所以我们不需要做其他任何事情,只需要从我们
的 sequence 对象创建一个新的集合。换句话说,对于 sequence 中的每个值,检查它是否已
经在集合中所花费的时间将是常数:
sequence = [‘a’, ‘a’, ‘b’, ‘c’, ‘c’, ‘d’]
result = set(sequence)
result
set([‘a’, ‘c’, ‘b’, ‘d’])
这将复杂度降低到了 O(n),这是集合对象创建的复杂度。额外的优点是更短和更明确
的代码。
削减外部调用,减少工作负载
复杂度的一部分是由调用其他函数、方法和类引入的。一般来说,尽可能多的把代码
放在循环之外。这对于嵌套循环更是加倍的重要。如果一些计算可以在循环开始之前进行,
就不要一次又一次地重复计算。内部循环要尽量保持紧凑。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值