Python中最快的排序方式

Posted

技术标签:

【中文标题】Python中最快的排序方式【英文标题】:Fastest way to sort in Python 【发布时间】:2011-04-20 19:27:27 【问题描述】:

在 Python 中对大于 0 且小于 100000 的整数数组进行排序的最快方法是什么?但不使用 sort 等内置函数。

我正在研究根据输入大小组合 2 个运动功能的可能性。

【问题讨论】:

为什么不使用内置函数? 什么是最快的到达道路但不驾驶保时捷的方法? @Anders:不要重新发明***。内置的 sort() 应该足以满足您的情况。 我很好奇:为什么需要实现自己的排序例程?这对我来说就像是家庭作业:-) @Aaron - 或者更重要的是 - 在不使用任何类型的预制车辆的情况下,最快的方式是什么;) 【参考方案1】:

桶大小 = 1 的桶排序。内存为 O(m),其中 m = 被排序的值的范围。运行时间为 O(n),其中 n = 被排序的项目数。当用于记录计数的整数类型有界时,如果任何值出现超过 MAXINT 次,此方法将失败。

def sort(items):
  seen = [0] * 100000
  for item in items:
    seen[item] += 1
  index = 0
  for value, count in enumerate(seen):
    for _ in range(count):
      items[index] = value
      index += 1

【讨论】:

【参考方案2】:

我可能有点迟到了,但是https://www.linkedin.com/pulse/sorting-efficiently-python-lakshmi-prakash有一篇有趣的文章比较了不同的种类

其中一个主要收获是,虽然默认排序效果很好,但我们可以使用快速排序的编译版本做得更好。这需要 Numba 包。

这里是 Github 存储库的链接: https://github.com/lprakash/Sorting-Algorithms/blob/master/sorts.ipynb

【讨论】:

【参考方案3】:

@fmark 我针对来自http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Python 的python 快速排序编写的python 合并排序实现的一些基准测试 并从最佳答案。

    列表的大小与列表中数字的大小无关

合并排序获胜,但是它使用内置的 int() 来地板

import numpy as np
x = list(np.random.rand(100))


# TEST 1, merge_sort 
def merge(l, p, q, r):
    n1 = q - p + 1
    n2 = r - q
    left = l[p : p + n1]
    right = l[q + 1 : q + 1 + n2]

    i = 0
    j = 0
    k = p
    while k < r + 1:
        if i == n1:
            l[k] = right[j]
            j += 1
        elif j == n2:
            l[k] = left[i]
            i += 1
        elif  left[i] <= right[j]:
            l[k] = left[i]
            i += 1
        else:
            l[k] = right[j]
            j += 1
        k += 1

def _merge_sort(l, p, r):
    if p < r:
        q = int((p + r)/2)
        _merge_sort(l, p, q)
        _merge_sort(l, q+1, r)
        merge(l, p, q, r)

def merge_sort(l):
    _merge_sort(l, 0, len(l)-1)

# TEST 2
def quicksort(array):
    _quicksort(array, 0, len(array) - 1)

def _quicksort(array, start, stop):
    if stop - start > 0:
        pivot, left, right = array[start], start, stop
        while left <= right:
            while array[left] < pivot:
                left += 1
            while array[right] > pivot:
                right -= 1
            if left <= right:
                array[left], array[right] = array[right], array[left]
                left += 1
                right -= 1
        _quicksort(array, start, right)
        _quicksort(array, left, stop)

# TEST 3
def qsort(inlist):
    if inlist == []: 
        return []
    else:
        pivot = inlist[0]
        lesser = qsort([x for x in inlist[1:] if x < pivot])
        greater = qsort([x for x in inlist[1:] if x >= pivot])
        return lesser + [pivot] + greater

def test1():
    merge_sort(x)

def test2():
    quicksort(x)

def test3():
    qsort(x)

if __name__ == '__main__':
    import timeit
    print('merge_sort:', timeit.timeit("test1()", setup="from __main__ import test1, x;", number=10000))
    print('quicksort:', timeit.timeit("test2()", setup="from __main__ import test2, x;", number=10000))
    print('qsort:', timeit.timeit("test3()", setup="from __main__ import test3, x;", number=10000))

【讨论】:

【参考方案4】:

如果您对渐近时间感兴趣,那么计数排序或基数排序可以提供良好的性能。

但是,如果您对挂钟时间感兴趣,您将需要使用您的特定数据集比较不同算法之间的性能,因为不同的算法在不同的数据集上表现不同.在这种情况下,它总是值得尝试快速排序:

def qsort(inlist):
    if inlist == []: 
        return []
    else:
        pivot = inlist[0]
        lesser = qsort([x for x in inlist[1:] if x < pivot])
        greater = qsort([x for x in inlist[1:] if x >= pivot])
        return lesser + [pivot] + greater

来源:http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Python

【讨论】:

很好的建议,除了变量列表的选择,这可能会导致很好的错误。我发布了其他更快的版本。 对同一组变量运行两次列表推导可能也不是最佳的。 @Tony Veijalainen “计算机科学中只有两件难事:缓存失效和命名”——我已经更改了变量名【参考方案5】:
def sort(l):
    p = 0
    while(p<len(l)-1):
        if(l[p]>l[p+1]):
            l[p],l[p+1] = l[p+1],l[p]
            if(not(p==0)):
                p = p-1
        else:
            p += 1
    return l

这是我创建的算法,但速度非常快。只是做排序(l) l 是您要排序的列表。

【讨论】:

冒泡排序【参考方案6】:

从理论上讲,基数排序以线性时间运行(排序时间大致与数组大小成正比增长),但实际上快速排序可能更适合,除非您要对绝对庞大的数组进行排序。

如果想让快速排序快一点,可以在数组变小时使用插入排序]。

理解算法复杂性和 Big-O 表示法的概念可能也会有所帮助。

【讨论】:

当你说数组变小是指小于64? 我会说少于 10 个,但没有正确答案;最好的办法是尝试不同的值,看看哪个更快。【参考方案7】:

我们可以使用字典的计数排序来最小化额外的空间使用,并保持运行时间低。由于 python 与 C 的实现开销,对于小尺寸的输入数组,计数排序要慢得多。当数组(COUNT)的大小约为 100 万时,计数排序开始超过常规排序。

如果您真的想为较小尺寸的输入带来巨大的加速,请在 C 中实现计数排序并从 Python 中调用它。

(修复了 Aaron (+1) 帮助捕获的错误...) 下面的仅 python 实现比较了这两种方法...

import random
import time

COUNT = 3000000

array = [random.randint(1,100000) for i in range(COUNT)]
random.shuffle(array)

array1 = array[:]

start = time.time()
array1.sort()
end = time.time()
time1 = (end-start)
print 'Time to sort = ', time1*1000, 'ms'

array2 = array[:]

start = time.time()
ardict = 
for a in array2:
    try:
        ardict[a] += 1
    except:
        ardict[a] = 1

indx = 0
for a in sorted(ardict.keys()):
    b = ardict[a]
    array2[indx:indx+b] = [a for i in xrange(b)]
    indx += b

end = time.time()
time2 = (end-start)
print 'Time to count sort = ', time2*1000, 'ms'

print 'Ratio =', time2/time1

【讨论】:

+1 Ratio = 1.16710428623 在我的机器上。巧妙地使用字典。值得注意的是,将 dict 构造阶段从 try: ardict[a] += 1; except: ardict[a] = 1 更改为 if a in ardict: ardict[a] += 1; else: ardict[a] = 1 会将比率降低到 Ratio = 0.696179723863 有时(通常)最好在跳跃之前先查看。我知道这样做是因为try 仅比if 便宜,如果很少发生异常。一个实际的例外仍然非常昂贵。 很遗憾这个算法是错误的。试试array = [1,10, 100, 1000, 10000, 100000, 1000000]。在未记录的实施细节上滑冰的危险再次发生。 感谢 aaron - 修复了不排序 dict 键的错误。那应该放慢一点。但是,如果与数组大小相比,不同元素的数量较低,它将保持其几乎 O(n) 的性质。我希望看到不同元素的 3D 图,数组长度为 x 和 y 维度以及运行时间与第 3 维度的比率。也许我会在一两天内完成。 @Aaron:在我的比赛中,(尝试,除外)效果更好。我先用(if then else)方式对其进行编码,然后切换到(try, except)以加快速度。此外,删除错误的版本比前一个版本运行得更快 - 因为在排序键中使用了底层 C 排序。那是免费的啤酒。 :-) 对我来说,例外解决方案也更快,如果不需要生成列表(因为它是可变的),则使用带有生成器的元组生成更快:array2=tuple(a for a in sorted(ardict) for i in xrange(ardict[a]))【参考方案8】:

Python 的早期版本混合使用了samplesort(一种具有大样本量的快速排序变体)和二进制插入排序作为内置排序算法。这被证明有些不稳定。 S0,从 python 2.3 开始使用adaptive mergesort 算法。

归并排序的顺序(平均)=O(nlogn)。 合并排序顺序(最差)=O(nlogn)。 但是快速排序的顺序(最差)= n*2

如果你使用list=[ .............. ]

list.sort() 使用mergesort algorithm.

对于排序算法之间的比较,您可以阅读wiki

详细对比comp

【讨论】:

是timsort,比mergesort更具适应性 Timsort 是一种自适应、稳定、自然的归并排序。【参考方案9】:

内置函数是最好的,但是因为你不能使用它们,所以看看这个:

http://en.wikipedia.org/wiki/Quicksort

【讨论】:

【参考方案10】:

既然你知道数字的范围,你可以使用Counting Sort,它在时间上是线性的。

【讨论】:

(我没有投反对票)。请注意,如果整数数组明显小于 100000,这不是一个好的算法,因为它会浪费内存(从而浪费时间)来构造 100000 个元素的列表。

以上是关于Python中最快的排序方式的主要内容,如果未能解决你的问题,请参考以下文章

通过服务器排序并确定最快 ping 的简化方式

按邮政编码距离升序计算和排序用户的最快方式(也是最优化的)

打造 Go 语言最快的排序算法

以最快的方式重新排序字母以按字典顺序排在第一位

在各类算法中那种算法排序是最快的?

数百万 UINT64 RGBZ 图形像素的最快排序算法