为什么平分比排序慢

时间:2016-07-26 18:29:21

标签: python algorithm performance sorting

我知道bisect正在使用二进制搜索来保持列表排序。但是我做了一个定时测试,正在读取和排序这些值。但是,与我的知识相反,保持价值然后对它们进行排序可以通过高差异赢得时机。有经验的用户可以解释一下这种行为吗?这是我用来测试时间的代码。

import timeit

setup = """
import random
import bisect
a = range(100000)
random.shuffle(a)
"""

p1 = """
b = []
for i in a:
    b.append(i)
b.sort()
"""

p2 = """
b = []
for i in a:
    bisect.insort(b, i)
"""

print timeit.timeit(p1, setup=setup, number = 1)
print timeit.timeit(p2, setup=setup, number = 1)

# 0.0593081859178
# 1.69218442959
# Huge difference ! 35x faster.

在第一个过程中,我逐个取值而不是仅仅排序a以获得类似文件读取的行为。并且非常努力地击败平分。

4 个答案:

答案 0 :(得分:4)

在bisect情况下,你的算法复杂度会更差......

bisect案例中,您有N个操作(每个操作的平均费用为log(N)以查找插入点,然后再添加O(N)个步骤以插入项目)。 总体复杂度:O(N^2)

使用sort,您只需一个Nlog(N)步骤(加上N O(1)步骤即可构建列表。 总复杂程度:O(Nlog(N))

另请注意,sort是在非常优化的C代码中实现的(bisect并非经过优化,因为它最终会更频繁地调用各种比较函数...)

答案 1 :(得分:3)

对列表进行排序大约需要O(N*log(N))次。将N个项目附加到列表需要O(N)次。连续执行这些操作大约需要O(N*log(N))次。

将列表平分需要O(log(n))次。将项目插入列表需要O(N)次。在for循环中同时执行N次需要O(N * (N + log(n))) == O(N^2)次。

O(N^2)O(N*log(N))更差,因此您的p1p2更快。

答案 2 :(得分:1)

要了解时差,让我们来看看你在那里做了什么。

在第一个示例中,您将获取一个空列表,并将项目附加到该列表,并在最后对其进行排序。

附加到列表非常便宜,它有一个amortized time complexity的O(1)。它不可能是真正的恒定时间,因为底层数据结构,一个简单的数组,最终需要随着列表的增长而扩展。这种情况经常发生,导致分配新数组并复制数据。这有点贵。但总的来说,we still say this is O(1)

接下来是排序。 Python正在使用Timsort这非常有效。这是平均和最差情况下的O(n log n)。总的来说,我们在O(n log n)之后得到恒定的时间,因此排序是唯一重要的事情。总的来说,这非常简单且非常快。

第二个示例使用bisect.insort。这利用列表和二进制搜索来确保列表始终排序

基本上,在每个插入中,它将使用二进制搜索来找到插入新值的正确位置,然后正确地移动所有项目以在该索引处为新值腾出空间。二进制搜索很便宜,O(log n)平均,所以这不是问题。单独转移也不是那么困难。在最坏的情况下,我们需要将所有项目向右移动一个索引,因此我们得到O(n)(这基本上是insert operation on lists)。

所以总的来说,我们会得到最差的线性时间。但是,我们在每次迭代上执行此操作。因此,当插入n元素时,我们每次都有O(n)。这导致二次复杂度O(n 2)。这是一个问题,最终将使整个事情变慢。

那么这告诉我们什么? Sorted inserting到列表中以获得排序结果并不是真正有效。当我们只进行一些操作时,我们可以使用bisect模块来保存已经排序的列表,但是当我们实际上有未排序的数据时,更容易对整个数据进行排序。

答案 3 :(得分:0)

有时,数据结构中的插入和删除操作可能会非常昂贵,特别是如果传入数据值的分布是随机的。然而,排序可能意外地快速。

一个关键的考虑因素是你是否能够积累所有价值,"然后将它们排序一次,然后一次性使用排序后的结果""如果可以,那么排序几乎总是非常快。

如果你还记得那些古老的科幻电影(当电脑被称为#34;大脑和#34;以及电影总是有旋转的磁带机时),那就是那种处理方式。据说:将排序的更新应用于也已排序的主磁带,以生成新的仍然排序的主服务器。不需要随机访问。 (这是一件好事,因为当时我们真的无法做到。)是处理大量数据的有效方式。