python - 序列的sort方法 与 bisect.insort, heapq.heappush 效率比较
大家讲道理
大家讲道理 2017-04-17 13:27:14
0
1
577
import time import bisect,heapq,random def sort1(n): "sort1 : bisect" lst = [] for i in xrange(n): bisect.insort_left(lst,random.randint(1,10000)) return lst def sort2(n): "sort2 :lst.sort" lst = [] for i in xrange(n): lst.append(random.randint(1,10000)) lst.sort() return lst def sort3(n): "sort3 : heapq" lst = [] for i in xrange(n): heapq.heappush(lst,random.randint(1,10000)) return lst for i in [sort1,sort2,sort3]: time1 = time.clock() i(100000) time2 = time.clock() time_all = time2-time1 print i.__doc__,time_all

输出结果:

sort1 : bisect 2.49 sort2 :lst.sort 0.36 sort3 : heapq 0.42

为什么bisect, heapq反而比内置方法 sort 还要慢?

大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

全部回复 (1)
黄舟

1.bisect

根据insort_left的文档:

Keep in mind that the O(log n) search is dominated by the slow O(n) insertion step.

也就是说,单次insort_left的时间复杂度是O(n),自然sort1的复杂度就变成了O(n^2),它最慢是应当的。

2.sort

文档说是O(n log n)的复杂度。从 listsort 详细文档来看,开发人员着实没少下了工夫。

3.heappush

根据维基百科,插入操作的时间复杂度是O(log n),所以总的时间复杂度仍然是O(n log n)。不过有一点值得注意,插入操作的平均时间是O(1),所以有可能会稍微快一点。

Python vs. PyPy

CPython 2.7

sort1 : bisect 2.617674 sort2 :lst.sort 0.295187 sort3 : heapq 0.39279

PyPy 2.4

sort1 : bisect 1.31 sort2 :lst.sort 0.043 sort3 : heapq 0.029

注,我把你的调用部分复制了一遍,执行了两次,结果为第二次的输出。

可以看得出,O(n log n)算法的耗时是在同一个数量级上的,但 CPython 中sort胜出,PyPy 中heapq 胜出。

cProfile

cProfile来测试,先看一下 CPython 的结果:

CPythonlst.sort:

400007 function calls in 0.935 seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 100000 0.325 0.000 0.386 0.000 random.py:175(randrange) 1 0.211 0.211 0.933 0.933 t.py:11(sort2) 100000 0.203 0.000 0.590 0.000 random.py:238(randint) 100000 0.071 0.000 0.071 0.000 {method 'append' of 'list' objects} 1 0.062 0.062 0.062 0.062 {method 'sort' of 'list' objects} 100000 0.061 0.000 0.061 0.000 {method 'random' of '_random.Random' objects}

CPythonheapq:

400006 function calls in 1.091 seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 100000 0.348 0.000 0.439 0.000 random.py:175(randrange) 1 0.228 0.228 1.089 1.089 t.py:19(sort3) 100000 0.212 0.000 0.651 0.000 random.py:238(randint) 100000 0.210 0.000 0.210 0.000 {_heapq.heappush} 100000 0.091 0.000 0.091 0.000 {method 'random' of '_random.Random' objects}

可以看出,相同操作消耗的时间差不太多,不同的地方在于sort用了62msappend用了71ms,总共是133ms;而相比之下,heappush用了210ms。再根据之前 PyPy 的迹象,这里怀疑 CPython 和heapq的 C 实现在多次互相调用中有一些解释器相关的“额外”代码。

最后再看一下 PyPy 的情况。

PyPylst.sort:

400007 function calls in 0.071 seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.025 0.025 0.071 0.071 t.py:11(sort2) 1 0.018 0.018 0.018 0.018 {method 'sort' of 'list' objects} 100000 0.011 0.000 0.019 0.000 random.py:172(randrange) 100000 0.008 0.000 0.008 0.000 {method 'random' of 'Random' objects} 100000 0.006 0.000 0.006 0.000 {method 'append' of 'list' objects} 100000 0.005 0.000 0.023 0.000 random.py:235(randint)

PyPyheapq:

1156196 function calls in 0.171 seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.047 0.047 0.171 0.171 t.py:19(sort3) 100000 0.034 0.000 0.070 0.000 heapq.py:242(_siftdown) 228095 0.031 0.000 0.036 0.000 heapq.py:135(cmp_lt) 100000 0.013 0.000 0.013 0.000 {method 'append' of 'list' objects} 100000 0.012 0.000 0.098 0.000 heapq.py:140(heappush) 100000 0.011 0.000 0.017 0.000 random.py:172(randrange) 100000 0.009 0.000 0.026 0.000 random.py:235(randint) 100000 0.006 0.000 0.006 0.000 {method 'random' of 'Random' objects} 228095 0.005 0.000 0.005 0.000 {hasattr} 100000 0.002 0.000 0.002 0.000 {len}

情况发生了变化!PyPy 的heapq实现是纯 Python 的,依托 PyPy 的性能来达到飞一般的效果。不过,在增加了cProfile的钩子之后,大量的函数调用计数变成了瓶颈,增加了heapq算法的时间消耗。

总结

n^2的算法毋庸置疑最慢,但同样是n log n,依次插入方式的堆排序可能会比内置的sort函数稍快一些,但因为 CPython 本身的一些限制无法体现。

    最新下载
    更多>
    网站特效
    网站源码
    网站素材
    前端模板
    关于我们 免责声明 Sitemap
    PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!