Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么max比sort慢?_Python_Sorting_Max_Python Internals - Fatal编程技术网

Python 为什么max比sort慢?

Python 为什么max比sort慢?,python,sorting,max,python-internals,Python,Sorting,Max,Python Internals,我发现max比Python2和3中的sort函数慢 Python 2 $ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]' 1000 loops, best of 3: 239 usec per loop $ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'max(a)'

我发现
max
比Python2和3中的
sort
函数慢

Python 2

$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 239 usec per loop
$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'max(a)'        
1000 loops, best of 3: 342 usec per loop
Python 3

$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 252 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a)'
1000 loops, best of 3: 371 usec per loop

为什么
max
O(n)
)比
sort
函数(
O(nlogn)
)慢?

在Python中使用
timeit
模块时必须非常小心

python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
在这里,初始化代码运行一次以生成随机数组
a
。然后,代码的其余部分将运行几次。第一次对数组进行排序时,但每隔一次对已排序的数组调用sort方法时。只返回最快的时间,因此实际上您正在计时Python对已排序的数组进行排序所需的时间

Python排序算法的一部分是检测数组何时已经部分或完全排序。当完全排序后,它只需在数组中扫描一次即可检测到这一点,然后停止

如果您尝试过:

python -m timeit -s 'import random;a=range(100000);random.shuffle(a)' 'sorted(a)[-1]'
然后在每个定时循环上进行排序,您可以看到对数组进行排序的时间确实比只找到最大值要长得多


编辑:@skyking's解释了我未解释的部分:
a.sort()
知道它正在处理列表,因此可以直接访问元素
max(a)
适用于任何任意iterable,因此必须使用泛型迭代。

这可能是因为
l.sort
列表的成员,而
max
是泛型函数。这意味着
l.sort
可以依赖
list
的内部表示,而
max
必须通过通用迭代器协议

这使得
l.sort
的每个元素提取都比
max
的每个元素提取快

我假设如果您改为使用排序(a)
,您将得到比
max(a)
慢的结果,请注意,虽然。显然,使用迭代器是一项重要的开销,这就是为什么您会观察到计时上的差异

然而,除此之外,你的测试是不公平的。您在同一列表上多次运行
a.sort()
。专门设计用于快速处理已(部分)排序的数据。您的测试表明该算法运行良好

这些都是公平的测试:

$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a[:])'
1000 loops, best of 3: 227 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a[:].sort()'
100 loops, best of 3: 2.28 msec per loop
在这里,我每次都要创建一份列表。正如您所看到的,结果的数量级是不同的:正如我们所期望的,微与毫秒


记住:大Oh指定一个上限!Python排序算法的下限是Ω(n)。O(n logn)并不自动意味着每次运行都需要与n logn成比例的时间。它甚至不意味着它需要比O(n)算法慢,但这是另一回事。需要了解的是,在某些有利的情况下,O(n logn)算法可能会在O(n)时间或更短的时间内运行。

a.sort()
在适当的位置工作。尝试
sorted(a)
@AndreaCorbellini,但sorted(a)需要
O(n)
内存,max(a)只需要one@WeizhongTu但是,
sort
sort,然后,
a
进行排序,这也是值得注意的:python使用了Timsort。此算法对已排序的列表执行
n-1
比较,这与
max
必须执行的数字相同。事实上,即使输入是“部分排序”的,Timsort也会进行O(n)比较。其他算法可能需要O(nlogn)时间,即使在已排序的情况下也是如此。我从来没有意识到解释器状态在代码运行期间是保留的。现在我想知道我在过去制作了多少错误的基准测试。:-}这对我来说是显而易见的。但请注意,即使对已排序的数组进行排序,也必须检查所有元素。这和获得最大值的工作量一样多。。。。在我看来,这似乎是半个答案。@KarolyHorvath,你是对的。我认为@skyking得到了另一半答案:
a.sort()
知道它正在处理列表,因此可以直接访问元素
max(a)
在任意序列上工作,不需要使用泛型迭代。@KarolyHorvath也许分支预测可以解释为什么重复排序排序的数组更快:@JUnitorCompressor解释“它在许多类型的偏序数组上具有超自然的性能(比需要的lg(N!)比较少,并且只有N-1次)”然后继续解释各种血腥的优化。我认为它可以做出许多
max
无法做到的假设,即排序不是渐进地快。这个假设离变得更具体只有一行时间了。不要质疑你的知识,只是这样一个添加对于那些不知道它的人来说是微不足道的。你是正确的,
sorted(a)
max(a)
慢。毫不奇怪,它的速度与
a.sort()
的速度差不多,但您对其原因的猜测——这是因为OP在测试中犯了一个错误,正如公认的答案所指出的。问题是,通用迭代器协议有可能有足够的开销来抵消
日志(n)
将复杂性考虑在内。这是一个
O(n)
算法,对于足够大的
n
(例如,因为每个操作的时间在算法之间可能不同-
nlogn
快速步骤可能比
n
慢速步骤快)。在这种情况下,没有考虑盈亏平衡的确切位置(但应该注意,
logn
因子对于smallish
n
来说不是一个很大的因子)。