当前位置: 首页 > 知识库问答 >
问题:

为什么max比排序慢?

闻人景澄
2023-03-14

我发现 max 比 Python 2 和 3 中的排序函数慢。

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

蟒蛇 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

为什么<code>max</code>(<code>O(n)</code>)比<code>sort</code>函数(<code<O(nlogn)</code>)慢?

共有3个答案

白萧迟
2023-03-14

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

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

我假设如果你改用sorted(a),你会得到比max(a)慢的结果。

卢毅
2023-03-14

首先,请注意max()使用迭代器协议,而list.sort()使用即席代码。显然,使用迭代器是一个重要的开销,这就是您观察时间差异的原因。

但是,除此之外,您的测试是不公平的。您多次在同一列表上运行 a.sort()。Python 使用的算法专门设计为对已经(部分)排序的数据快速处理。您的测试表明该算法正在很好地完成其工作。

这些是公平的测试:

$ 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

在这里,我每次都创建一个列表的副本。正如你所看到的,结果的数量级是不同的:如我们所预期的,微秒与毫秒。

记住:big-Oh指定了一个上限!Python的排序算法的下限是ω(n)。成为O(n log n)并不自动意味着每次运行花费的时间与n log n成比例。它甚至不意味着它需要比O(n)算法慢,但那是另一个故事。重要的是要理解,在一些有利的情况下,O(n log n)算法可以在O(n)时间或更短时间内运行。

宗安翔
2023-03-14

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

python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'

这里,初始化代码运行一次,以产生随机数组< code>a。然后剩余的代码运行几次。第一次它对数组进行排序,但是每隔一次你在一个已经排序的数组上调用sort方法。只返回最快的时间,所以您实际上是在计时Python对一个已经排序的数组进行排序需要多长时间。

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

如果您尝试:

python -m timeit -s 'import random;a=range(100000);random.shuffle(a)' 'sorted(a)[-1]'

然后排序发生在每个计时循环上,您可以看到对数组进行排序的时间确实比仅找到最大值要长得多。

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

 类似资料:
  • 我有2列制表符分隔的整数,其中第一列是随机整数,第二列是标识组的整数,可以由此程序生成。() 然后,我使用第二个程序()计算每个组的和。 如果我在给定大小的数据集上运行这些程序,然后打乱相同数据集的行的顺序,打乱的数据计算总和的速度比有序数据快2倍或更多。 我本来希望按组排序的原始数据具有更好的数据局部性并且速度更快,但我观察到相反的行为。我想知道是否有人可以假设原因?

  • 我有一个表,其中有(其他20个)列、和,以及和的索引。该表有大约500k行。 为什么以下to查询在速度上差异如此之大?查询A需要0.3秒,而查询B需要28秒。 查询A 我使用MySQL5.1.34。

  • 我已经在链接中看到了(http://bigocheatsheet.com/)插入排序的复杂性与冒泡排序相同,堆排序也优于这两种排序。但是,当我创建一个示例程序并比较插入排序所花费的时间时,我感到难以置信。 类用于测试排序算法。 泡泡排序类 用于插入排序的类 堆排序类 用于创建数组的类 我尝试了所有的情况,比如最好的情况、最坏的情况和一般情况。但在所有情况下,插入排序都比冒泡排序和堆排序快得多。理论

  • 问题内容: 这是一段C ++代码,显示了一些非常特殊的行为。由于某些奇怪的原因,奇迹般地对数据进行排序使代码快了将近六倍: 不使用std::sort(data, data + arraySize);,代码将在11.54秒内运行。 使用排序的数据,代码将在1.93秒内运行。 最初,我认为这可能只是语言或编译器异常,所以我尝试了Java: 具有类似但不太极端的结果。 我首先想到的是排序将数据带入缓存,

  • 我一直在玩Java 8 ,我决定对 和 流进行微基准测试。正如预期的那样, 的速度是原来的两倍,但还是出现了其他一些问题--如果我在将数据传递给 之前先对其进行排序,则与传递未排序列表相比, Map->Collect/code>得到结果所需的时间要多出5-8倍。 下面是一个更好的基准测试代码 结果也是相似的: 那么,我的问题是为什么过滤一个未排序的列表比过滤一个已排序的列表更快呢?

  • 我正在维基百科上阅读关于外部排序的文章,我需要理解为什么两阶段合并比一阶段合并更有效。 Wiki:但是,单次合并有一个限制。随着区块数量的增加,我们将内存分成更多的缓冲区,因此每个缓冲区都较小,因此我们必须进行许多较小的读取,而不是较少的较大读取。 因此,对于100 MB内存中的50 GB的排序,使用单个合并过程是没有效率的:磁盘需要用500个数据块中的每个数据块(我们一次从每个数据块读取100M