我并不陌生,但我并没有太多使用Python,而且我的知识相当广泛而且语言也不是很深,也许这里知识渊博的人可以回答我的问题。当我需要将项目添加到列表并将其按照添加的项目进行排序时,我发现自己处于这种情况。快速做到这一点的方法是。
list.append(item) // O(1)
list.sort() // ??
我想如果这是项目添加到列表的唯一方式,我希望排序相当有效,因为列表是按每次添加进行排序的。然而,这也有效:
inserted = False
for i in range(len(list)): // O(N)
if (item < list[i]):
list.insert(i, item) // ??
inserted = True
break
if not inserted: list.append(item)
有谁可以告诉我,其中一个显然更有效率?我倾向于第二组陈述,但我真的不知道。
答案 0 :(得分:6)
您正在寻找的是bisect模块,最有可能的是insort_left
所以你的表达式可以等同地写成
这
some_list.append(item) // O(1)
some_list.sort() // ??
到
bisect.insort_left(some_list, item)
答案 1 :(得分:2)
除了接近结尾处的任何地方插入需要O(n)时间,因为它必须移动(复制)插入点之后的所有元素。但另一方面,所有基于比较的排序算法平均必须进行Omega(n log n)比较。许多类型(包括Python使用的timsort)在许多输入上都会做得更好,可能包括你的(“几乎排序”的情况)。他们仍然必须移动至少尽可能多的元素插入正确的位置。他们还需要完成相当多的额外工作(检查所有元素以确保它们的顺序正确,加上更复杂的逻辑,通常可以提高性能,但不是在你的情况下)。由于这些原因,它可能更慢,至少对于大型列表而言。
由于用C语言编写(在CPython中;但类似的推理适用于其他Pythons),它可能仍然比Python编写的线性扫描更快。这留下了如何找到插入点的问题。二进制搜索可以在O(log n)时间内完成这一部分,所以它在这里非常有用(当然,插入仍然是O(n),但是如果你想要一个排序列表,就没办法解决这个问题)。不幸的是,二进制搜索实现起来相当棘手。幸运的是,它已经在标准库中实现:bisect
。